- Published on
argocd-image-updaterがLocal Docker Registryで動かなかった
Table of Contents
Summary
argocd-image-updaterは特定の条件下で Local Docker Registry(e.g. 192.168.0.100:32000)の複数のイメージを Application を更新できない問題があります。 この記事は問題の概要と解決策の簡単なメモです。
結論としては、:
を含むレジストリ名を使ってはいけません。
もし詳細を知りたい人はコメントで教えて下さい。尚、私は kubernetes を勉強中なので誤りがある可能性があります。
Background
- 趣味の kubernetes 環境をローカルマシンで動かしている
- Docker Registry も、ECR や GCR ではなく、ローカルで動かしている
- アプリケーションの CI には tekton、CD には argocd を利用している
- argocd で使う manifest の images の更新を自動化するために、argocd-image-updater を使いたかった
Environment
- kubernetes
- created by microk8s
- work on local machine
- Container Registry
- Use local registry created by microk8s (
microk8s enable registry
) - work on NodePort of kubernetes like 192.168.0.100:32000 (default configurations)
- Use local registry created by microk8s (
- argocd
- v2.5.5+fc3eaec
- argocd-image-updater
- v0.12.1
Issue
2 つ以上の Local Registry のイメージを指定した Kustomize を利用する Application で、1 つのイメージしか更新されない問題があります。 ただしイメージが Local Registry(192.168.0.100.32000)である点に注意してください。
この manifest は、以下の 2 つのイメージを最新に自動更新する設定です。
- 192.168.0.100:32000/api-server
- 192.168.0.100:32000/app
CI がイメージを Push すると、argocd-image-updater が自動的に最新のイメージをデプロイすることが期待されます。 argocd-image-updater のログや Event では2つのイメージが期待通り更新されていましたが、結果は 192.168.0.100:32000/app のみ更新されました。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: 192.168.0.100:32000/api-server,192.168.0.100:32000/app
argocd-image-updater.argoproj.io/force-update: 'true'
argocd-image-updater.argoproj.io/update-strategy: latest
argocd-image-updater.argoproj.io/write-back-method: git
argocd-image-updater.argoproj.io/git-branch: main
argocd-image-updater.argoproj.io/write-back-target: kustomization
spec:
project: myapp
source:
repoURL: git@github.com:tkat0/xxx.git
targetRevision: HEAD
path: kubernetes/myapp/development
syncPolicy:
automated:
prune: true
selfHeal: true
destination:
server: https://kubernetes.default.svc
namespace: default
Solution
:
を含むレジストリ名を使ってはいけません。 そのため、以下の解決案があります。
- Option1: 192.168.0.101 のようなポートを含まない URI で Local Registry を公開する
- 今回はこちらを採用
- Option2: GCR, ECR などを利用する
Option1 では、単純に Local Registry の Service を LoadBalancer にして、192.168.0.101 のようなアドレスで直接アクセスできるようにするだけでも十分だと思いますが、私は Ingress を利用して Local Docker Registry を以下のように設定しました。
- (required) Ingress で
/
で Service を公開 - (required) nginx.ingress.kubernetes.io/proxy-body-size: "0"
- (optional) host には自分のドメインを設定(cr.cluster.tkat0.dev)
- 利便性のため(尚、このホストは LAN 内のクラスタを解決するように設定していて、public ではない)
- https://sslip.io/ のような wild card DNS でも問題ないはず
- (optional) microk8s の registry の利用を辞め、helm で registry をデプロイ
- できる限り manifest を Git 管理したいため
以下が Local Registry のマニフェストです。argocd 経由で helm の twuni/docker-registry をインストールし、Ingress を追加しています。(helm chart の設定次第では、すべて Application 内の記述で完結できるかもしれません)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cr
namespace: ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: 'false'
# NOTE: 413 Request Entity Too Large:
# https://github.com/kubernetes/ingress-nginx/issues/4825#issuecomment-721911893
# https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#custom-max-body-size
# 0 means no upper bound
nginx.ingress.kubernetes.io/proxy-body-size: '0'
spec:
ingressClassName: nginx
rules:
- host: cr.cluster.tkat0.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: docker-registry
port:
number: 5000
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: docker-registry
namespace: argocd
spec:
project: default
source:
chart: docker-registry
# https://github.com/twuni/docker-registry.helm
repoURL: https://helm.twun.io
targetRevision: 2.2.2
helm:
releaseName: docker-registry
parameters:
- name: service.type
value: ClusterIP
- name: garbageCollect.enabled
value: 'true'
- name: persistence.size
value: 20Gi
- name: ingress.enabled
value: 'false'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
destination:
server: https://kubernetes.default.svc
namespace: docker-registry
Cause
原因は、argocd の実装に起因します。
argocd は、Kustomize のイメージを比較するときに最初の:
までをイメージの識別子として扱うため、192.168.0.100:32000/api-server と 192.168.0.100:32000/app を同じイメージ(192.168.0.100)として誤って認識します。
具体的には、argocd-image-updater は、func SetKustomizeImage の中で Application を更新しています。 このメソッドが呼ばれるたびに、1 つずつイメージを Application に追加することが期待されます。
しかし、func (*ApplicationSourceKustomize) MergeImage とfunc (KustomizeImage) Matchでイメージを追加するのではなく、上書きしていることがわかりました。
なぜなら、前述の通り:
までが同じであればを同じイメージだと判断するためです。
一般的には、gcr.io/project/image-1:v1.0 と gcr.io/project/image-2:v1.0 のようなイメージは別物と判断されますが、ポートを含む Local Registry では、この問題が起こります。
レジストリの指定にコロンを含むことは特に production 環境では一般的ではないことは理解できますが、仕様として含んではいけない、という記述は見つけることはできませんでした(もし知っている方がいれば教えて下さい)。 少なくとも、以下では:8080 を含んでも良いように見えます。
https://docs.docker.com/engine/reference/commandline/tag/
The hostname must comply with standard DNS rules, but may not contain underscores. If a hostname is present, it may optionally be followed by a port number in the format
:8080
Conclusion
この記事では、私が直面した argocd-image-updater が Local Registry で動かない問題について説明しました。
情報を整理して近日中にコミュニティに報告する予定です。
update(Jan 7): 報告済み https://github.com/argoproj-labs/argocd-image-updater/issues/516