2024.07.09
GitHub ActionsでCI/CDを実験してみる
こんにちは。次世代システム研究室のK.X.D.です。
はじめに
ソースコード管理といえば、今ではGithubがすぐに思い浮かぶでしょう。
GitHub上でCI/CD実現できる機能はGithub Actionsです。
ソースコード管理しながら、外部サービス連携しなくても、CI/CD運用するのはとても便利と思いますので、
Github Actionsの実験を積んで、もっと自由に活用したいと思います。
やりたいこと:
Githubのアクティビティ(PR作成、PRマージなど)により、CI/CDを自動化にしたいと思います。
具体的に、下記のような作業が実施したいです。
- Docker ContainerでGolangのRevelアプリケーションを動かす
- Githubでソースコード管理して、PRを作成すると自動テスト実行(CIワークフロー実現)
- PRをMainへマージすると、自動でContainerイメージを作成して公開する(CDワークフロー実現)
- Github上のリリースタグを自動作成する
実装:
早速実装に入りたいと思います。
アプリケーション環境作成:
DockerFile
FROM golang:1.21-alpine
# Install dependencies
RUN apk --no-cache --update add \
tzdata \
ca-certificates \
openssh \
git \
wget \
curl
# Install command line tools
RUN go install github.com/revel/cmd/[email protected]
ENV PATH $PATH:/go/bin
EXPOSE 9000
RUN mkdir -p /go/src
COPY init.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/init.sh
WORKDIR "/go/src"
CMD ["init.sh"]
init.sh
#!/bin/bash
app_name="myapp"
cd /go/src
# 起動
revel run -a ${app_name}か
下記の手順でRevelアプリケーションを生成する
docker build --no-cache -t github-action-revel . docker run -it -p 9000:9000 -v ./src:/go/src --name github-action-revel -d github-action-revel /bin/sh docker exec github-action-revel "revel new app" git init
実行結果

Github Actionsのワークフローファイル作成するために、.githubのフォルダを作成しておく
CI/CDワークフロー作成
.github下にworkflows/ci.yml, workflows/cd.ymlファイル作成

- workflows/ci.yml
CIファイルで実装したことは、
[opened, synchronize]のトリガーでMainブランチマージ先のPRを作成また、新いCommitがあると、ジョブを動かす
testジョブは、UnitTestでソースコードのロジック検証する
golangciジョブは、GolangのLintでソースコードの文法、適切さまで検証する
ジョブの特別設定がなければ、デフォルトは並列で実行されてる
name: CI
on:
pull_request:
branches:
- main
types: [opened, synchronize]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up containers
run: |
docker build --no-cache -t github-action-revel .
docker run -it -p 9000:9000 -v ./src:/go/src --name github-action-revel -d github-action-revel /bin/sh
- name: Run tests
run: docker exec github-action-revel sh -c 'revel test myapp dev'
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: stable
cache-dependency-path: src/myapp/gosum
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.59
working-directory: src/myapp
problem-matchers: true
画面上に実行


Lintで通せない場合、「problem-matchers: true」の設定で問題あったソースコードまで表示される

- workflows/cd.yml
cd.ymlは、自動テストとレビューを通すと、Mainにマージして、即時リリースのCDを実現するためのワークフロー
Mainへのマージをトリガーにして、下記の作業を実施する
- Containerイメージをビルドする
- Containerレジストリに公開する(今回は、Githubのレジストリを利用する)
- 公開した後に、リリースタグ生成して、GITHUB_TOKENで登録する
release、create-release-tagsの2ジョブは、通常のジョブデフォルト挙動が並列で実行してますが、
release、create-release-tagsは順次に実行したいですので、「needs: release」でreleaseジョブ実行完了した後に、create-release-tags実行するようにしてます。
記述したものの中で重要な項目を説明します。
「permissions: write-all」:Githubレジストリに公開権限付与ため設定
concurrency: group: ${{ github.workflow }}:同じワークフローで2重で実行されると、前に実行したワークフローをキャンセルする
secrets.GITHUB_TOKEN:ワークフローを実行すると、Githubリソースアクセスためのトークンが自動に生成されています。
name: CD
on:
pull_request:
types: [closed]
branches:
- main
workflow_dispatch:
permissions: write-all
concurrency:
group: ${{ github.workflow }}
env:
DOCKER_IMAGE_NAME: github-action-revel
RELEASE_BRANCH: main
jobs:
release:
# マージされたときのみ実行
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# Githubレジストリにログインする
- name: 'Login to GitHub Container Registry'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{github.actor}}
password: ${{secrets.GITHUB_TOKEN}}
- id: repository_lowercase
name: Repository to lowercase
run: |
echo "repository=${GITHUB_REPOSITORY@L}" >> $GITHUB_OUTPUT
- name: Build docker image
run: docker build -t ghcr.io/${{ steps.repository_lowercase.outputs.repository }}/${{ env.DOCKER_IMAGE_NAME }}:latest .
- name: Push Docker Image
run: docker push ghcr.io/${{ steps.repository_lowercase.outputs.repository }}/${{ env.DOCKER_IMAGE_NAME }}:latest
create-release-tags:
if: github.event.pull_request.merged == true
needs: release
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
# 前回のリリースタグを取得する
- name: Get previous tag
id: pre_tag
run: |
echo "pre_tag=$(curl -H 'Accept: application/vnd.github.v3+json' -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r .tag_name)" >> $GITHUB_OUTPUT
# タグを生成する 「{YYYY.MM.DD}-{当日リリース回数}」
- name: Generate release tag
id: release_tag
env:
TZ: 'Asia/Tokyo'
run: |
today=$(date +'%Y.%m.%d')
pre_release_date=$(echo ${{ steps.pre_tag.outputs.pre_tag }} | awk -F'-' '{print $1}')
pre_release_count=$(echo ${{ steps.pre_tag.outputs.pre_tag }} | awk -F'-' '{print $2}')
if [[ ! $pre_release_date = $today ]]; then
echo "init count"
pre_release_count=0
fi
echo "release_tag=$today-$(($pre_release_count + 1))" >> $GITHUB_OUTPUT
# リリースタグを作成する
- name: Create Release
run: |
curl -X POST \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-d "{ \"tag_name\": \"${{ steps.release_tag.outputs.release_tag }}\", \"target_commitish\": \"${{ env.RELEASE_BRANCH }}\", \"name\": \"${{ steps.release_tag.outputs.release_tag }}\", \"body\": \"Release for ${{ steps.release_tag.outputs.release_tag }}\"}" \
https://api.github.com/repos/${{ github.repository }}/releases
release、create-release-tagsの2ジョブは順次に実行

releaseジョブ実行

「ghcr.io/{repogistory}/github_actions_revel/github-action-revel:latest」のURLで公開確認

create-release-tagsジョブ実行

まとめ
今回のブログでは、実際の業務に関する作業をGithub Actionsで実験しました。
Githubを利用するあたって自動化が必要な作業は色々あって、その場でGithub Actionsで活用を提案したいと思います。
また、実際にGithub Actionsの処理でエラーが発生した時にどうすればカバできるかなども考えないといけないです。
それらのケース対策はGithub Actionsは十分に提供されていますが、ブログの内容に挟めると長くなりますので、省略させていただきます。
Github Actionsを作成の際に、異常なケースでも考慮して、完璧なGithub Actionsを設計いただくと良いと思います。
最後に
グループ研究開発本部 次世代システム研究室では、最新のテクノロジーを調査・検証しながらインターネット上の高度なアプリケーション開発を行うエンジニア・アーキテクトを募集しています。募集職種一覧からご応募をお待ちしています。
グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。
Follow @GMO_RD

