Skip to main content

2 posts tagged with "skaffold"

View All Tags

· 5 min read
Shunsuke Suzuki

skaffold を用いてマニフェストを動的に生成しつつ GitOps する方法を考えたので紹介します。 なお、現時点ではあくまで考えてみただけで実際に導入したりはしていません。

GitOps はマニフェストを Git リポジトリにコミットしないといけないわけですが、 Docker image をビルド、プッシュし、マニフェストの image tag を書き換えるという一連の処理をどうやってやるのがいいのか 個人的に考えていました。

自分は FluxCD には詳しくないのですが、 FluxCD では registry をポーリングして自動で最新のタグに書き換える機能があるそうですね。

https://toolkit.fluxcd.io/guides/image-update/

ただし、まだ alpha であることと、 semver に従っていないといけないようです。 これだと master branch が update されるたびに image をビルドして sha でタグを付与するみたいな運用は難しそうです。

Skaffold だとマニフェストの image tag を自動で書き換えてくれる機能があります。 加えて skaffold render コマンドを使うと manifest の apply はせずにファイルへの出力だけやってくれます。 出力された manifest を Git リポジトリに commit, push すれば GitOps が実現できそうです。

How

リポジトリを 2 つ用意します。

  • app: アプリケーションのコードとマニフェストを管理するリポジトリ
  • manifest: GitOps が連携するマニフェストを管理するリポジトリ

app は Monorepo になっているとします。ディレクトリ構成は次のような感じをイメージしています。

services/
foo/
skaffold.yaml
Dockerfile
kubernetes/
base/
kustomization.yaml
deployment.yaml
overlays/
develop/
kustomization.yaml
production/
kustomization.yaml

skaffold.yaml

---
apiVersion: skaffold/v2beta10
kind: Config
build:
tagPolicy:
gitCommit:
prefix: develop-
artifacts:
- image: foo
deploy:
kustomize:
paths:
- kubernetes/overlays/develop
profiles:
- name: production
build:
tagPolicy:
gitCommit:
prefix: production-
deploy:
kustomize:
paths:
- kubernetes/overlays/production

profile によって develop と production を区別しています。

manifest では tag を指定しないようにします。

    spec:
containers:
- name: foo
image: foo

skaffold render で manifest を生成します。

$ skaffold render \
-p production \
--default-repo xxx.dkr.ecr.ap-northeast-1.amazonaws.com \
--offline=true \
--loud=true \
--output manifest.yaml

--loud=true をつけないとなにも出力しないのでなにが起こってるのかわかりません。

生成されたマニフェストをみると tag が自動で付与されています。

      - image: xxx.dkr.ecr.ap-northeast-1.amazonaws.com/foo:production-e3a42e0@sha256:7032af912c511ab0c8353c28604461d8960833144953fb50853f087db55ffdd0

生成した manifest を manifest リポジトリに commit, push します。 manifest リポジトリを checkout してきて git コマンドでやることもできますが、 ghcp を使うとコマンド1つでできるので便利です。

manifest リポジトリは対象のサービス及び環境ごとにブランチを分けることにします。 そうしたほうが push の際に失敗しにくいと思います(多分。分からないけど)。

$ ghcp commit -u suzuki-shunsuke -r manifest -b "foo/production" -m "message" manifest.yaml

message は実際にはもっと詳細なメッセージにすべきでしょう。 CI で実行することになると思うので、 build URL を含めたりすると良いでしょう。

こうすると foo/production ブランチに manifest.yaml が push されます。 あとは ArgoCD や FluxCD のような GitOps ツール で foo/production の manifest.yaml をデプロイすればよいはずです。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: foo
namespace: argocd
spec:
source:
repoURL: https://github.com/suzuki-shunsuke/manifest.git
targetRevision: foo/production
path: manifest.yaml
destination:
server: https://kubernetes.default.svc
namespace: production

さいごに

以上、 Skaffold を使っていい感じに tag を書き換えて GitOps する仕組みを考えてみました。 Skaffold 使うと Docker image の build, push といった一連の流れも全部やってくれるので楽で良いなと感じました。

GitOps じゃなくても CIOps でも Skaffold でデプロイすると便利そうだなと思いました。 その場合は skaffold render ではなく、 skaffold run になりそうですね。

https://skaffold.dev/docs/workflows/ci-cd/

· 7 min read
Shunsuke Suzuki

自作の CLI ツール skaffold-generator の紹介です。 プロトタイピングみたいなノリで半日くらいで割と手早く作れました。 名前が長くて適当なのでもっと良い名前ないかなと思ってます。

Skaffold に欲しい機能がないので補完する感じで作ったのですが、「それ〇〇で出来るよ」とかあったら(GitHub issue とか Twitter で)教えていただけると幸いです。

どんなツールか

設定ファイル skaffold-generator.yaml を監視して変更があったら skaffold.yaml を生成するツールです。設定ファイルでサービスの依存関係を定義できたり、コマンドライン引数で指定したサービス及びそれが依存するサービスに関連した設定だけを使って skaffold.yaml を更新します。 このツールは skaffold.yaml を生成するだけなので実際にアプリケーションをビルド・デプロイするには skaffold と組み合わせて使います。

なぜ作ったか

元々ローカルでアプリケーションを動かしながら開発するために Docker Compose を使ってるリポジトリがあるのですが、それを skaffold に移行出来ないか検証しています。 まだ skaffold を触り始めたばかりで理解が浅いのですが、 本番環境は k8s で動いてるからローカルも k8s で動かせるといいかなと思ったり、あとは変更を検知して自動でビルド・デプロイしてくれたりして便利そうかなと思いました。 まぁ結果的に移行しないことになったとしても、 Skaffold と現状の仕組みについて理解が深まればいいかなくらいのつもりです。

検証の過程で、 以下のようなことが Docker Compose だと出来るけど Skaffold だと難しそうだと思いました。

  • サービスの依存関係を定義すること
    • Skaffold というより k8s の問題かとは思いますが
    • Docker Compose だと依存するものを自動で起動してくれて便利
  • コマンドライン引数で指定したサービスだけ起動すること
    • Skaffold だと skafffold.yaml で定義したものすべてがビルド・デプロイされるという認識

サービスの数が少なければ全部ビルド・デプロイでもいいですが、 マイクロサービスをモノレポで管理しているような場合、 すべてのマイクロサービスをビルド・デプロイするのは無駄が大きかったりします。

そこで skaffold.yaml の元となる設定ファイルを用意し、コマンドライン引数でサービスを指定して必要最小限の skaffold.yaml を生成するツールを作ってみました。

インストール

Go のバイナリをダウンロードしてきてください。 https://github.com/suzuki-shunsuke/skaffold-generator/releases

使い方

使い方は簡単です。サブコマンドもありません。 リポジトリにサンプルがあるのでそれを見ましょう。

まずは skaffold-generator.yaml を用意します。

skaffold-generator.yamlbaseservices からなります。

base は生成される skaffold.yaml のベースとなるものです。 deploy.kubectl.manifestsbuild.artifacts は上書きされるので指定しないでください。

services ではサービスのリストを定義します。 各サービスは以下の属性を持ちます。

  • name: サービス名。コマンドライン引数と depends_on でサービスを指定するのに使う。ユニークにする
  • manifests: skaffold.yaml の deploy.kubectl.manifests
  • artifacts: skaffold.yaml の build.artifacts
  • depends_on: サービスが依存するサービス名のリスト

用意したら skaffold-generator を実行します。 skaffold.yaml が生成(既にあれば上書き)され、 skaffold-generator.yaml の変更を監視した状態になります。

$ skaffold-generator
2020/04/05 18:19:37 start to watch skaffold-generator.yaml

コマンドライン引数でサービス名を指定しない場合、すべてのサービスが skaffold.yaml に反映されます。 別のターミナルで skaffold dev を実行すれば 生成された skaffold.yaml を使ってアプリケーションをビルド・デプロイ出来ます。

$ skaffold dev

skaffold-generator.yaml を変更すれば、その変更を検知し skaffold.yaml が更新され、そして skaffold devskaffold.yaml の変更を検知しアプリケーションがビルド・デプロイされます。

引数無しですべてのサービスをデプロイするとこのツールの意味がないので、コマンドライン引数でサービス名を指定しましょう。

$ skaffold-generator api

こうするとサービス apiapi が依存するサービス(依存関係は再帰的に処理されます)だけが skaffold.yaml に反映されます。 依存関係は循環してても大丈夫です。

使い方は以上です。

Docker Compose みたいにできないこと

Docker Compose みたいに依存関係を定義できるようになりましたが、 Docker Compose みたいにデプロイの順序は考慮されません。 まぁこのツールは skaffold.yaml を生成するだけなので仕方ないですね。

最後に

以上、 skaffold-generator の紹介でした。 まだ作ったばっかで自分でも使えてないので本当に使い物になるのかは分かりませんが、 興味ある人は触ってみてください。