Ritolabo
  1. Home
  2. Kubernetes
  3. ArgoCD
  4. Argo CD で Kubernetes 上のアプリを公開する

Argo CD で Kubernetes 上のアプリを公開する

  • 公開日
  • カテゴリ:ArgoCD
  • タグ:Kubernetes,ArgoCD,学習メモ
Argo CD で Kubernetes 上のアプリを公開する

Kubernetes で動かしているアプリを外から開けるようにするには、Deployment のほかに Service・Ingress が必要になる。

この記事では、これらの YAML を Argo CD が見ている Git のディレクトリに追加して push し、kubectl apply を実行せずに http://localhost/ でページが表示される状態にする。

contents

  1. 前提
  2. 今回作る構成
  3. Ingress Controller(Contour)を入れる
    1. kind 向けの設定を 1 つ追加する
  4. Git に置く YAML
    1. ConfigMap: ページの内容
    2. Deployment: ConfigMap をページの置き場所に差し込む
    3. Service: Pod への宛先
    4. Ingress: リクエストをどの Service に渡すか
  5. push して反映する
  6. ConfigMap を変えて push する
  7. 全体像
  8. 用語メモ
  9. 参考 URL

前提

GitHub の private リポジトリ argocd-study に web/deployment.yaml(nginx の Deployment web。replicas: 1)があり、Argo CD の Application web がそれを default namespace に入れている状態から始める。Argo CD は v3.5.5。

Application web の spec.syncPolicy には automated・selfHeal: true・prune: true が書いてあり、Git に push すれば人が操作しなくても反映される。

$ kubectl get applications -n argocd
NAME   SYNC STATUS   HEALTH STATUS
web    Synced        Healthy

$ kubectl get deployment,pods -n default
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web   1/1     1            1           2d

NAME                       READY   STATUS    RESTARTS   AGE
pod/web-557577df75-5m5lr   1/1     Running   2          2d

クラスタは kind で作ったもので、localhost の 80 番ポートへのアクセスが 1 つ目の Worker Node の 80 番に届く設定(kind の extraPortMappings)にしてある。この時点では、Worker Node の 80 番で待っているプログラムがないので、http://localhost/ を開いても何も返らない。

$ curl -i http://localhost/
curl: (52) Empty reply from server

この記事で使う Argo CD の用語。

言葉意味
SyncGit の YAML をクラスタに apply すること。自分で kubectl apply を実行する代わりに、Argo CD が実行する
Synced / OutOfSyncGit の YAML とクラスタの中身を比べた結果。同じなら Synced、違えば OutOfSync
Healthy / Progressingクラスタに入れたものが動いているかを、Argo CD が種類ごとに判定した結果(kubectl get applications の HEALTH STATUS 列)。Deployment なら Pod が全部準備できていれば Healthy、途中なら Progressing。Application 全体の Health は、中のもので一番悪いものになる
Argo CD の画面ブラウザで開く管理画面。kubectl port-forward svc/argocd-server -n argocd 8080:443 を実行して https://localhost:8080 を開く

今回作る構成

Git の web/ ディレクトリに置くファイルは 4 つ。

ファイル作るもの役割
web/configmap.yamlConfigMap web-htmlブラウザに返すページ(index.html)の内容
web/deployment.yamlDeployment web(変更)nginx の Pod を作る定義。ページの置き場所に ConfigMap を差し込む
web/service.yamlService webnginx の Pod への宛先(名前と固定の IP)
web/ingress.yamlIngress web外から来たリクエストを、どの Service に渡すかの決まり

これとは別に、外から来たリクエストを受けてクラスタの中の Pod に渡すプログラム(Ingress Controller)が必要になる。実務では、Ingress Controller のようなクラスタの設備も、アプリとは別の Application にして Argo CD に入れさせる(Git で管理する)。この記事では学習のために Git には置かず、kubectl apply で入れる。Argo CD が反映するものをアプリの YAML だけにして、push したときに何がクラスタに入ったかを見やすくするため。

Ingress Controller(Contour)を入れる

クラスタの中の Pod には、クラスタの中だけで通じる IP アドレスが付いている。外のブラウザからその IP には届かない。外から届くようにするには、「外から来たリクエストを受けて、中の Pod に渡す」プログラムが必要で、これを Ingress Controller と呼ぶ。Ingress Controller は Kubernetes に含まれておらず、あとから選んで入れる。

今回は Contour を入れる。Contour は 2 つのプログラムでできている。

プログラム役割動く場所
envoyWorker Node の 80 番(と 443 番)で待ち、受けたリクエストを Pod に転送する(リバースプロキシ)Worker Node ごとに 1 つの Pod(DaemonSet)
contourクラスタの Ingress を読んで、envoy に転送先の設定を流し込むPod 2 つ(Deployment)

公式の install YAML を URL で apply する。namespace projectcontour、Deployment contour、DaemonSet envoy、Service、CRD、証明書を作る Job などが 1 ファイルに入っている(2026-10-17 時点で v1.33.7)。

$ kubectl apply -f https://projectcontour.io/quickstart/contour.yaml

$ kubectl get pods -n projectcontour
NAME                            READY   STATUS      RESTARTS   AGE
contour-859c5dcfdc-7ht29        1/1     Running     0          23s
contour-859c5dcfdc-z4ndk        1/1     Running     0          23s
contour-certgen-v1-33-7-xkd58   0/1     Completed   0          23s
envoy-fd26n                     2/2     Running     0          23s
envoy-qngq7                     2/2     Running     0          23s

contour が 2 つ、envoy が Worker Node の数だけ(2 つ)できる。contour-certgen-... は contour と envoy の間の通信に使う証明書を作って終了した Job で、Completed のままでよい。envoy の 2/2 は、Pod の中にコンテナが 2 つ(envoy 本体と、停止時の処理をする shutdown-manager)あることを表す。

kind 向けの設定を 1 つ追加する

Argo CD は、Ingress の Health を「Ingress に入口のアドレスが書き込まれているか」で判定する(公式ドキュメントでは status.loadBalancer.ingress が空でないこと)。クラウドでは、クラウドが用意した入口の IP アドレスを Contour が Ingress に書き込むが、手元の kind にはそれがない。そのままでは Ingress が Progressing のままになり、Application web 全体の Health も Progressing になる。

Contour には、書き込むアドレスを指定する設定 ingress-status-address がある。Contour の設定ファイルは ConfigMap contour(projectcontour namespace)の contour.yaml で、install YAML が作ったものは内容がすべてコメントになっている。これを次の YAML で置き換える。

apiVersion: v1
kind: ConfigMap
metadata:
  name: contour
  namespace: projectcontour
data:
  contour.yaml: |
    ingress-status-address: 127.0.0.1

contour は設定ファイルを起動時に読むので、apply したあとに起動し直す。

$ kubectl apply -f contour-configmap.yaml
# => configmap/contour configured

$ kubectl rollout restart deployment contour -n projectcontour
# => deployment.apps/contour restarted

ここまでで、Worker Node の 80 番で envoy が待つようになった。ただし、どこに渡すかの決まり(Ingress)がまだないので、http://localhost/ はまだ通らない。

Git に置く YAML

ConfigMap: ページの内容

image に入っている nginx の初期ページではなく、自分で書いた HTML を返したい。image を作り直さずに済ませるため、ファイルの内容を ConfigMap に置いて Pod に差し込む。

web/configmap.yaml。data の下が「ファイル名: 内容」で、| は次の行からの複数行をそのまま文字列にする YAML の書き方。

apiVersion: v1
kind: ConfigMap
metadata:
  name: web-html
data:
  index.html: |
    <h1>Hello from Git</h1>

Deployment: ConfigMap をページの置き場所に差し込む

ConfigMap を置いただけでは nginx は読まない。Deployment の YAML に、「ConfigMap web-html を、コンテナの /usr/share/nginx/html(nginx がページを読むディレクトリ)に置く」と書く。

web/deployment.yaml。変更したのは spec.template.spec の下の 2 か所で、containers の中に volumeMounts、containers と並べて volumes を追加した。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80
          volumeMounts:
            - name: html
              mountPath: /usr/share/nginx/html
      volumes:
        - name: html
          configMap:
            name: web-html
  • volumes: Pod に「html という名前で、ConfigMap web-html の内容をディスクのように見せる」
  • volumeMounts: コンテナの /usr/share/nginx/html に、その html を置く。ディレクトリの中身は ConfigMap にあるファイル(index.html)だけになる

Deployment の template(Pod の定義)が変わるので、push すると Pod が新しいものに入れ替わる。

Service: Pod への宛先

Pod の IP アドレスは、Pod が入れ替わるたびに変わる。入口の envoy に「この IP に渡す」とは書けない。Service は、「ラベル app: web が付いた Pod」への宛先で、名前(web)と変わらない IP(ClusterIP)が付く。

web/service.yaml。selector は Deployment の template.metadata.labels と同じ app: web。Service の 80 番に来たものを、Pod の targetPort(80 番。nginx が待っているポート)に渡す。

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80

Ingress: リクエストをどの Service に渡すか

envoy は Worker Node の 80 番で待っているが、「どのリクエストをどの Service に渡すか」を知らない。それを書くのが Ingress。

web/ingress.yaml。「パスが / で始まるリクエスト(Prefix。つまり全部)は、Service web の 80 番に渡す」という 1 つの決まりだけを書く。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

Ingress はデータで、これを読んで envoy に設定を流し込むのが contour。

push して反映する

4 ファイルを 1 回の push で GitHub に入れる。

$ git status --short
 M web/deployment.yaml
?? web/configmap.yaml
?? web/ingress.yaml
?? web/service.yaml

$ git add web
$ git commit -m "Add configmap, service, ingress"
$ git push

Argo CD は GitHub からファイルを定期的に取得する。既定では 2〜3 分に 1 回で、設定で変えられる。(すぐに反映したいときは、Argo CD の画面の REFRESH ボタンを押す)

別のターミナルで default namespace の Pod を -w 付きで表示しておくと、新しい Pod が作られて古い Pod が Terminating になるのが見える。

$ kubectl get pods -n default -w
NAME                   READY   STATUS    RESTARTS   AGE
web-557577df75-5m5lr   1/1     Running   2          2d
web-9f744d4b9-799pm    0/1     Pending             0   0s
web-9f744d4b9-799pm    0/1     ContainerCreating   0   0s
web-9f744d4b9-799pm    1/1     Running             0   1s
web-557577df75-5m5lr   1/1     Terminating         2   2d

default namespace に何ができたかを確認する。

$ kubectl get configmap,deployment,pods,svc,ingress -n default
NAME                         DATA   AGE
configmap/kube-root-ca.crt   1      2d13h
configmap/web-html           1      50s

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web   1/1     1            1           2d13h

NAME                      READY   STATUS    RESTARTS   AGE
pod/web-9f744d4b9-799pm   1/1     Running   0          50s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP   2d13h
service/web          ClusterIP   10.96.45.25   <none>        80/TCP    50s

NAME                            CLASS    HOSTS   ADDRESS     PORTS   AGE
ingress.networking.k8s.io/web   <none>   *       127.0.0.1   80      50s

$ kubectl get applications -n argocd
NAME   SYNC STATUS   HEALTH STATUS
web    Synced        Healthy
  • configmap/web-html、service/web、ingress.networking.k8s.io/web が、Git に書いたとおりの名前で作られた。Application web の path はディレクトリ(web)を指しているので、そこに追加したファイルは Application を変えなくても対象になる
  • Pod の名前が web-557577df75-... から web-9f744d4b9-... に変わった。Deployment の template が変わったため
  • Ingress の ADDRESS が 127.0.0.1 になっている。Contour に書かせた入口のアドレスで、これが入っているので Argo CD の Health が Healthy になる

http://localhost/ を開くと、web/configmap.yaml に書いた HTML が返る。

$ curl http://localhost/
<h1>Hello from Git</h1>
ブラウザで http://localhost を開くと Hello from Git と表示される

クラスタに対して自分で実行したのは Contour の apply だけで、アプリ(Deployment)とその公開に必要な設定(ConfigMap・Service・Ingress)は git push だけで入った。

Argo CD の画面で Application web を開くと、Application の下に ConfigMap・Service・Deployment・Ingress の 4 つが並び、Deployment の下に新旧の ReplicaSet と Pod がぶら下がっている。

Argo CD の画面。Application web の下に ConfigMap web-html、Service web、Deployment web、Ingress web が並ぶ

ConfigMap を変えて push する

web/configmap.yaml の HTML を変えて push し、Pod を入れ替えずにページが変わることを確認する。

$ git diff
-    <h1>Hello from Git</h1>
+    <h1>Hello again from Git</h1>

$ git commit -am "Change greeting"
$ git push

Argo CD が ConfigMap を apply しても、Pod は入れ替わらない。Pod が入れ替わるのは Deployment の template が変わったときだけで、ConfigMap の変更では template は変わらない。

代わりに、Pod のコンテナに置いてある index.html が少し遅れて新しい内容に置き換わる。Node で動く kubelet が定期的に ConfigMap を見直してファイルを差し替えるためで、この記事の環境では Sync から 1 分ほどかかった。nginx はリクエストのたびにファイルを読むので、差し替わった時点でページが変わる。

$ curl http://localhost/
<h1>Hello again from Git</h1>

$ kubectl get pods -n default
NAME                  READY   STATUS    RESTARTS   AGE
web-9f744d4b9-799pm   1/1     Running   0          7m54s
ブラウザで http://localhost を開くと Hello again from Git と表示される

Pod の名前も AGE も変わっていない。

全体像

自分が git push したあと、Argo CD が 4 つを apply した状態。curl http://localhost/ のリクエストは envoy が受けて、Ingress の決まりどおりに Service web の Pod へ転送される。(図の角が二重の箱は動くプログラム、それ以外の箱は etcd に保存されたデータ)

図を描画しています…

リクエストの通り道は、localhost の 80 番 → Worker Node の 80 番 → envoy → (Ingress の決まり)→ Service web → Pod web-xxxxx の nginx、の順。

用語メモ

用語読み方意味
Ingress Controllerイングレスコントローラー外から来たリクエストを受けて、クラスタの中の Pod に渡すプログラム。Kubernetes には含まれず、Contour などを選んで入れる
Ingressイングレスどのリクエストをどの Service に渡すかの決まり。etcd に保存されるデータで、Ingress Controller が読んで動く
Serviceサービスラベルで選んだ Pod への宛先。名前と固定の IP(ClusterIP)が付く
ConfigMapコンフィグマップ設定値やファイルの内容を入れておくデータ。Volume として Pod に差し込める
EnvoyエンボイContour が使っているリバースプロキシ。実際にリクエストを受けて転送する

まとめ

  • Application の path が指す Git のディレクトリに YAML を追加して push すれば、Application を変えなくてもクラスタに入る
  • 外から Pod に届くには、Ingress Controller(クラスタの設備として kubectl apply で入れる)と、Ingress・Service(Git に置く)の両方が必要
  • ConfigMap の内容を Git で変えて push しても Pod は入れ替わらず、kubelet がファイルだけを差し替える

参考 URL


[Prev] Argo CD の自動同期: automated・selfHeal・prune

Author

rito

rito

  • Backend Engineer
  • Tokyo, Japan
  • PHP 5 技術者認定上級試験 認定者
  • 統計検定 3 級