ArgoCD と Istio Ingress Gateway

ArgoCD という Kubernetes 用の CD ツールがあります。

Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.

これを Istio Ingress Gateway と共に使う方法をまとめます。それだけでそこそこの量になったので。

ArgoCD の deploy

argocd という namespace を作って、そこに Manifest を apply するだけです。

$ kubectl create namespace argocd
$ kubectl apply -n argocd -f [https://raw.githubusercontent.com/argoproj/argo-cd/v1.4.2/manifests/install.yaml](https://raw.githubusercontent.com/argoproj/argo-cd/v1.4.2/manifests/install.yaml)

これだけで起動します。次のように port-forward すれば https://localhost:8443/ でアクセスできます。

$ kubectl -n argocd port-forward svc/argocd-server 8443:443

HA 構成の場合は manifests/ha/install.yaml を使うようです。

$ diff -u \
    <(curl -s https://raw.githubusercontent.com/argoproj/argo-cd/v1.4.2/manifests/install.yaml) \
    <(curl -s https://raw.githubusercontent.com/argoproj/argo-cd/v1.4.2/manifests/ha/install.yaml)

HA の方は Redis sentinel で Redis が冗長構成になるようです。

ArgoCD 用 Istio Ingress の設定

ArgoCD は cli 用の gRPC とブラウザ向けの HTTP を同じサーバー、同じポートで処理しており、そこが Ingress 設定におけるポイントです。

TLS Passthrough

argocd-server はデフォルトで TLS 対応しているため、これをそのまま活かす方法です。

Gateway で port 443 を tls.mode: PASSTHROUGH とします。

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: argocd-gw
  namespace: argocd
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - argocd.example.com
    port:
      name: http
      number: 80
      protocol: HTTP
  - hosts:
    - argocd.example.com
    port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: PASSTHROUGH

VirtualService は argocd-gw (Gateway) と紐付け、argocd.example.com 宛て (https では SNI が必須) を argocd-server (Service) に転送します。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: argocd-vsvc
  namespace: argocd
spec:
  gateways:
  - argocd-gw
  hosts:
  - argocd.example.com
  http:
  - name: argocd-http
    route:
    - destination:
        host: argocd-server
  tls:
  - name: argocd-https
    match:
    - port: 443
      sniHosts:
        - argocd.example.com
    route:
    - destination:
        host: argocd-server

argocd の argocd-secret Secret に入っている証明書 (tls.crt と tls.key) を更新する必要があります。

argocd cli からもアクセス可能です。

$ argocd --server argocd.example.com:443 app list

TLS Termination (方法1)

Ingress で TLS を Termination した場合の設定方法です。argocd-server (Pod) へのアクセスは TLS を使わないため、argocd-server Deployment の設定を変更して argocd-server の起動オプションに --insecure を追加する必要があります。

$ kubectl -n argocd edit deployment argocd-server

command--insecure を追加します。これを追加しないと argocd-server が https でのアクセスを求めて redirect loop となります。

$ kubectl -n argocd patch deployment argocd-server -p '
{
  "spec": {
    "template": {
      "spec": {
        "containers": [
          {
            "name": "argocd-server",
            "command": ["argocd-server","--staticassets","/shared/app","--insecure"]
          }
        ]
      }
    }
  }
}'
  template:
    spec:
      containers:
      - command:
        - argocd-server
        - --staticassets
        - /shared/app
        - --insecure

Gateway で argocd.example.com を port 80 と port 443 で受け入れます。443 は tls.mode を SIMPLE とします。TLS の証明書と秘密鍵が必要となりますが、 istio-system namespace に argocd-certificate という名前の Secret が事前に作成されている前提です(ここの詳しい話は以前の投稿を参照)。argocd-server が --insecure の影響で https への redirect を行わなくなっているため、Gateway で port 80 のところに tls.httpsRedirect: true を入れてあります。これで 301 Redirect を返してくれます。

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: argocd-gw
  namespace: argocd
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - argocd.example.com
    port:
      name: http
      number: 80
      protocol: HTTP
    tls:
      httpsRedirect: true
  - hosts:
    - argocd.example.com
    port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: argocd-certificate

VirtualService で argocd.example.com 宛てを argocd-server (Service) に送ります。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: argocd-vsvc
  namespace: argocd
spec:
  gateways:
  - argocd-gw
  hosts:
  - argocd.example.com
  http:
  - name: http
    route:
    - destination:
        host: argocd-server

この方法では Ingress の Envoy と ArgoCD Pod の間を gRPC として処理しないため、argocd cli からアクセスする場合に --grpc-web オプションの指定が必要になります。

$ argocd --server argocd.example.com:443 --grpc-web app list

--grpc-web オプションをつけないと次のようなエラーとなります。

FATA[0000] rpc error: code = Internal desc = transport: received the unexpected content-type "text/plain; charset=utf-8"

TLS Termination (方法2)

先の方法(方法1)では gRPC が使えなくなってしまいましたが、User-Agent で判断して argocd コマンドからの場合は gRPC でアクセスできるようにします。

方法1と同じく argocd-server に --insecure の追加が必要です。

$ kubectl -n argocd patch deployment argocd-server -p '
{
  "spec": {
    "template": {
      "spec": {
        "containers": [
          {
            "name": "argocd-server",
            "command": ["argocd-server","--staticassets","/shared/app","--insecure"]
          }
        ]
      }
    }
  }
}'

さらに、argocd の manifest で作成されている argocd-server Service も編集します。port 443 の namegrpc に変更します。名前が重要。

$ kubectl -n argocd edit svc argocd-server
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  - **name: grpc**
    port: 443
    protocol: TCP
    targetPort: 8080

その上で、Gateway と VirtualServer を作成する

Gateway は方法1と同じ

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: argocd-gw
  namespace: argocd
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - argocd.example.com
    port:
      name: http
      number: 80
      protocol: HTTP
    tls:
      httpsRedirect: true
  - hosts:
    - argocd.example.com
    port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: argocd-certificate

VirtualService では User-Agent が argocd-client で始まる場合は grpc に名前を変更した port 443 に、それ意外は port 80 へ。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: argocd-vsvc
  namespace: argocd
spec:
  gateways:
  - argocd-gw
  hosts:
  - argocd.example.com
  http:
  - name: grpc
    match:
    - headers:
        user-agent:
          prefix: argocd-client
    route:
    - destination:
        host: argocd-server
        port:
          number: 443
  - name: http
    route:
    - destination:
        host: argocd-server
        port:
          number: 80

これでブラウザでも argocd cli からでも --grpc-web オプションなしでアクセス可能です。

Built with Hugo
テーマ StackJimmy によって設計されています。