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