🐙
k8s上のコンテナのイメージタグをGitHub ActionsとArgoCDで自動で書き換える
前提
- Kubernetesクラスタ上でwebアプリを動かしている
- ArgoCDが
release
ブランチと同期している -
main
ブランチに変更があったらマニフェストを書き換えてrelease
にpushする、という運用 -
app
ディレクトリにアプリケーションのコードがある -
manifests
ディレクトリにKubernetesマニフェストがある
イメージの差し替えについてはArgo CD Image Updaterというプラグインでも達成できるが今回は使わない。
ワークフロー例
name: Build-and-Push
on:
push:
branches:
- main
paths:
- app/**
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
fetch-depth: 0
- name: Fetch Git tags
run: |
git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Registry
uses: docker/login-action@v2
with:
registry: your.container.registry
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get current version
id: get_version
run: |
CURRENT_VERSION=$(git tag --sort=-version:refname | head -n 1)
echo "Current version: $CURRENT_VERSION"
echo "::set-output name=CURRENT_VERSION::$CURRENT_VERSION"
- name: Bump patch version
id: bump_version
run: |
CURRENT_VERSION="${{ steps.get_version.outputs.CURRENT_VERSION }}"
PATCH_VERSION=$(echo $CURRENT_VERSION | awk -F. '{print $3}')
NEW_PATCH_VERSION=$((PATCH_VERSION + 1))
NEW_VERSION=$(echo $CURRENT_VERSION | sed "s/\.[0-9]*$/.${NEW_PATCH_VERSION}/")
echo "New version: $NEW_VERSION"
echo "::set-output name=NEW_VERSION::$NEW_VERSION"
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: ./app
push: true
tags: |
your.container.registry/your-app:latest
your.container.registr/your-app:${{ steps.bump_version.outputs.NEW_VERSION }}
- name: Update Deployment and Application manifests
run: |
NEW_VERSION="${{ steps.bump_version.outputs.NEW_VERSION }}"
sed -i "s/your-app:v[0-9]*\.[0-9]*\.[0-9]*/your-app:$NEW_VERSION/g" manifests/your-app/deploy.yaml
- name: Commit and push changes
run: |
git config user.name "GitHub Actions Bot"
git config user.email "actions@github.com"
git -A
git status
git commit -m "Update image tag to ${{ steps.bump_version.outputs.NEW_VERSION }}"
git tag ${{ steps.bump_version.outputs.NEW_VERSION }}
git push origin --tags
git switch -c release
git push origin release --force
解説
最初はリポジトリにvX.X.X
というタグが存在している必要がある。あとは自動でタグがpushされる。
最新のタグを取得し、そこからパッチバージョンを1だけ上げる。
dockerイメージは、ビルドして最新+1のタグをつけた上で任意のレジストリにpushされる。
メジャーバージョン、マイナーバージョンを上げたければ手動でタグをpushすればいい。
イメージタグが書き換えられたマニフェストがrelease
ブランチにpushされる。
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
リポジトリにpushするためにrepo
権限が必要。
fetch-depth: 0
タグ情報を得るために必要。
CURRENT_VERSION=$(git tag --sort=-version:refname | head -n 1)
fetchしたタグの中から最新のものを抽出している。やり方が冗長な気もするがほかに思いつかなかった。
your.container.registry/your-app:latest
なくてもいい。なんとなくlatest
タグをつけておきたくなる。
git push origin release --force
コンフリクトで自動デプロイ失敗すると萎えるのでforceつけたい。リスクは高いので多分forceつけないほうがいい。
注意
set-output
はdeprecatedらしい。代わりに環境変数を使ったほうがいい。
Discussion