Edited at

GitHub Appを使ってGitOpsする

Kubernetes3 Advent Calendar 2018 - Qiita の16日目です。


概要

既存のKubernetes環境向けCDツールがチームの要件に満たなかったのでGitHub AppでGitOpsをしていくことにしました。ここではその内容を共有しています。

GitOpsについての詳細はこちら: GitOps


小さな仕組みでGitOpsをする


  • 一般的にあらゆるプロジェクトの持つ予算と残された時間はそれほど多くありません。kubernetesの持つメリットを享受しつつ素早くデプロイフローを作る必要があります。

  • 環境は大きく変化していくため、変化に強くありたいと願います。端的に言えば今しばらくはワークフローをシンプルでつまらないものに保つべきと考えています。


既存ツールなんかもさわってみたんですよ



  • ローカルで kubectlapply する


    • 2-3人の規模であれば問題は起こらないと思えます。ただし今は開発人数が増えてきていて、破綻が見えているか破綻します。



  • Spinnaker, Jenkins X, argo CDも触った


私が少し機能追加しようとすると面倒に思えました。

経験上もうしばらく時間を置けばデファクトが決まり技術も枯れて安定するはずで、それまでは待ちたいと思います。

正味、複数RepositoryとDockerRepositoryとGitHubと、Slack等の通知先とやり取りすれば良いので、さっとやってみることにしました。


GitHub Appを使ったワークフロー

以下のようなデプロイフローを想定します。

deploy_flow.png


  1. 開発者はPull RequestをApp repo のstagingブランチに出す

  2. 1.のPull Request がmergeされる

  3. Github Appは2のイベントを検知すると、App repoのstagngブランチを docker buildして docker pushする。

  4. Github Appはstagngブランチを Staging用のManifestを自動生成してManifest RepoへPull Requestを出す

  5. 4のPull Requestがmergeされる。

  6. Github Appは5のイベントを検知すると、mergeされた内容をstagingクラスタへkubectl applyする


使用する技術について


probotを使ったGitHub Appが仲介業をする

probotはNode.jsでeasyに作れるGitHub App FrameWorkです。

Probot | GitHub Apps to automate and improve your workflow

GitHub Webhookを受け取って特定の動作をさせることができ、独自でHTTPエントリポイントを作って任意の動作をさせることが可能です。

このporobotを利用したGitHub Appのサーバを立ててRepositoryへのdeploy keysやGKEの場合はGCPサービスアカウントへの認証を持たせると仲介者の役割を果たせます。

ex: stagingにmergeされたら処理する

    app.on('push', async context => {

const branch = context.payload.ref.split('/')[2] // format is "refs/heads/$BRANCH"
const repo = context.payload.repository.name
if (branch === 'staging' && repo === 'AppRepo') {
const result = someOps(branch, repo)
app.log(result)
}
})

ex: GitHubAppにkubectl applyさせるHTTPエンドポイント

  // kubectl apply action

const router = app.route('/github-app')
router.post('/apply', (req, res) => {
if (req.header('token') !== token) {
res.send('Recieved invalid token.') // check valid token
return
}
const result = someApplyExec()
app.log(result)
res.send(`k8s Applied.`)
})


KustomizeとシェルスクリプトでManifestを自動生成する

例えばDeploymentを以下のようなシェルスクリプトで作り、kustomize buildすればテンプレート的に作れそうです。

cat << EOS > $FILE_NAME

apiVersion: "extensions/v1beta1"
kind: "Deployment"
metadata:
name:
$DEPLOYMENT
spec:
replicas:
$REPLICA
selector:
matchLabels:
app:
$APP
template:
metadata:
labels:
app:
$APP
spec:
containers:
- name:
$NAME
image:
$IMAGE
ports:
- containerPort: 80
EOS


その他: 本番環境や他サービス連携

productionの場合は図1.のPullRequestのheadをstagingに、baseをproductionにします。

Slackにイベントの通知を流したい場合はGitHubAppの処理に記述を入れます。


終わりに:

今回のフロー自体には手間を感じ得ますが、それぞれの仕組みはシンプルでくだらない、分かりやすいものになります。

シェルスクリプトかJavaScriptの知識とそれからGitHubやKubernetesのAPIを眺めればその日のうちに修正を入れることができます。

私はこの仕組に全くこだわりがありません。デファクトが出たら/dev/nullにアーカイブするでしょう。

引き続きプロダクトとその先にいる顧客に集中したいと思っています。