Amazon Web Services ブログ
Contour で EKS Ingress を保護し、Let’s Encrypt の GitOps 方法を学びます
Weaveworks の Stefan Prodan 氏によるゲスト投稿です。
Kubernetes の用語で、Ingress は、クラスターの外部からクラスター内で実行されているサービスへの HTTP(S) ルートを公開します。Ingress は、負荷分散と SSL/TLS 終了を実行しながら、Kubernetes サービスに外部から到達可能な URL を提供するように構成できます。
Kubernetes には Ingress リソースが付属しており、ELB Ingress Controller や NGINX などの Ingress 仕様を実装するコントローラがいくつかあります。Kubernetes Ingress の仕様は非常に限られているため、ほとんどのコントローラはアノテーションを使用してルーティング機能を Ingress が許可する基本範囲を超えて拡張する必要がありました。ただし、アノテーションを使用しても、名前空間間のルーティングや加重負荷分散など、解決できない制限がいくつかあります。
Contour (今後 CNCF プロジェクト) は、Envoy に基づいた最新の Ingress コントローラで、HTTPProxy という名前の新しい仕様で Ingress API の機能を拡張します。HTTPProxy API は、より豊かなユーザー体験を可能にし、マルチテナント環境での Ingress の使用制限に対処します。
HTTPProxy 仕様は、HTTP ヘッダーまたは Cookie フィルターに基づいた高度な L7 ルーティングポリシー、および Kubernetes サービス間の加重負荷分散を促進するのに十分な柔軟性を備えています。これらの機能を備えているため、Contour は、Flagger を使用した Canary リリースおよび A/B テストの自動化に適しています。
このガイドでは、GitOps パイプラインをセットアップして HTTPS を介して Kubernetes サービスを安全に公開する方法を示します。
- Amazon EKS および Amazon Route 53
- TLS 証明書をプロビジョニングするための、Let’s Encrypt での cert-manager
- Ingress コントローラとしての Contour
- GitOps オペレーターとしての Flux
- デモウェブアプリケーションとしての podinfo
EKS クラスターを作成する
ローカルにインストールされた AWS アカウント、GitHub アカウント、git
、kubectl
、eksctl が必要です。最初に、4 つの EC2 ノードで EKS クラスターを作成します。
cat << EOF | eksctl create cluster -f -
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: eu-west-1
nodeGroups:
- name: controllers
labels: { role: controllers }
instanceType: m5.large
desiredCapacity: 2
iam:
withAddonPolicies:
certManager: true
albIngress: true
taints:
controllers: "true:NoSchedule"
managedNodeGroups:
- name: workers
labels: { role: workers }
instanceType: m5.large
desiredCapacity: 2
volumeSize: 120
EOF
上記のコマンドで、2 つのノードグループを持つ EKS クラスターを作成します。
- コントローラノードグループには、cert-manager で DNS01 ACME チャレンジを解決するために必要な IAM ロールがあり、Contour および cert-manager と共に Envoy プロキシ DaemonSet を実行するために使用されます。
- ワーカー管理対象ノードグループは、アプリ用として、Envoy によってクラスターの外部に公開されます。
Kustomize パッチは、セレクターとトレレーションを使用してノードグループのワークロードを固定するために使用されます。例:
# contour/node-selector-patch.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: envoy
namespace: projectcontour
spec:
template:
spec:
nodeSelector:
role: controllers
tolerations:
- key: controllers
operator: Exists
Kustomize パッチを使用して、元のマニフェストを変更しないようにします。マニフェストを更新するには、./scripts/update-manifests.sh
を実行します。このスクリプトは、最新の cert-manager と Contour YAML をダウンロードし、リポジトリ内のマニフェストを上書きします。
Flux をインストールする
Flux は Kubernetes の GitOps オペレーターであり、クラスターの状態を Git リポジトリと同期させます。Flux はプルベースであり、Kubernetes 内でも実行されるため、運用環境の外部でクラスターの認証情報を公開する必要はありません。
Kubernetes YAML マニフェストを使用してクラスターの目的の状態を定義し、Kustomize を使用してカスタマイズできます。Flux は、引き続きクラスターに目的の状態を適用する制御ループを実装し、デプロイの削除やポリシーの変更などの有害なアクションに対する保護を提供します。
プラットフォームに応じて、fluxctl をインストールします。
# macOS
brew install fluxctl
# Windows
choco install fluxctl
# Linux
curl -sL https://fluxcd.io/install | sh
GitHub で、このリポジトリをフォークし、ローカルで複製します (stefanprodan
を GitHub ユーザー名に置き換えます):
git clone https://github.com/stefanprodan/eks-contour-ingress
cd eks-contour-ingress
次に、次を使用して fluxcd
名前空間を作成します。
kubectl create ns fluxcd
そして、フォーク URL を指定して Flux をインストールします (そして、再び stefanprodan
を GitHub ユーザー名に置き換えます):
export GHUSER="stefanprodan" && \
fluxctl install \
--git-user=${GHUSER} \
--git-email=${GHUSER}@users.noreply.github.com \
--git-url=git@github.com:${GHUSER}/eks-contour-ingress \
--git-branch=master \
--manifest-generation=true \
--namespace=fluxcd | kubectl apply -f -
Git 同期をセットアップ
Flux は起動時に SSH キーを生成し、パブリックキーを記録します。以下でパブリックキーを見つけます。
fluxctl identity --k8s-fwd-ns fluxcd
クラスターの状態を git と同期するには、パブリックキーをコピーし、GitHub リポジトリに書き込みアクセスを使用してデプロイキーを作成する必要があります。
GitHub を開き、リポジトリに移動して、[設定] > [デプロイキー] に移動し、[デプロイキーを追加] をクリックして、[書き込みアクセスを許可] のチェックをオンにし、Flux パブリックキーを貼り付けて [キーを追加] をクリックします。
数秒後、Flux はクラスターに Contour、cert-manager、podinfo をデプロイします。watch kubectl get pods --all-namespaces
で同期ステータスを確認できます。
DNS を構成する
Contour の Envoy ロードバランサーの外部アドレスを取得します。
$ kubectl get -n projectcontour service envoy -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP
envoy LoadBalancer 10.100.228.53 af4726981288e11eaade7062a36c250a-1448602599.eu-west-1.elb.amazonaws.com
外部アドレスを使用して、Route53 で CNAME レコードを作成します。LB アドレス *.example.com
にマップします。
host
コマンドを使用して DNS 設定を確認します。
$ host podinfo.example.com
podinfo.example.com is an alias for af4726981288e11eaade7062a36c250a-1448602599.eu-west-1.elb.amazonaws.com.
Let’s Encrypt ワイルドカードの証明書を取得する
Let’s Encrypt から証明書を取得するには、ドメイン DNS レコードを制御できることを証明する特定のコンテンツを含む TXT レコードを作成して、所有権を証明する必要があります。DNS チャレンジと証明書の更新は、cert-manager と Route 53 を使用して完全に自動化できます。
次に、Let’s Encrypt DNS01 ソルバーを使用してクラスターの問題を作成します (stefanprodan
を GitHub ユーザー名に置き換えます)。
export GHUSER="stefanprodan" && \
cat << EOF | tee ingress/issuer.yaml
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
annotations:
fluxcd.io/ignore: "false"
spec:
acme:
email: ${GHUSER}@users.noreply.github.com
privateKeySecretRef:
name: letsencrypt-prod
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- dns01:
route53:
region: eu-west-1
EOF
projectcontour
名前空間で証明書を作成します (example.com
をご使用のドメインに置き換えます):
export DOMAIN="example.com" && \
cat << EOF | tee ingress/cert.yaml
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: cert
namespace: projectcontour
annotations:
fluxcd.io/ignore: "false"
spec:
secretName: cert
commonName: "*.${DOMAIN}"
dnsNames:
- "*.${DOMAIN}"
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
EOF
次に、GitOps の方法である git
を使用して変更を適用します。
git add -A && \
git commit -m "add wildcard cert" && \
git push origin master && \
fluxctl sync --k8s-fwd-ns fluxcd
Flux は git<->cluster
調整を 5 分ごとに実行するため、上記の fluxctl sync
コマンドを使用して同期を高速化します。
証明書が発行されるまで待ちます (完了するまでに最大 2 分かかります)。
$ watch kubectl -n projectcontour describe certificate
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal GeneratedKey 2m17s cert-manager Generated a new private key
Normal Requested 2m17s cert-manager Created new CertificateRequest resource "cert-1178588226"
Normal Issued 20s cert-manager Certificate issued successfully
証明書が発行されると、cert-manager は TLS 証明書を使用してシークレットを作成します。次のようにご確認ください。
$ kubectl -n projectcontour get secrets
NAME TYPE DATA AGE
cert kubernetes.io/tls 3 5m40s
証明書を Contour 名前空間に保存して、異なる名前空間にデプロイされた複数のアプリで再利用できるようにします。
TLS を介したサービスを公開
デモアプリ podinfo
を公開し、クラスターの外部からアクセスできるようにするには、Contour の HTTPProxy カスタムリソース定義を使用します。
このために、TLS 証明書のシークレットを参照して HTTPProxy を作成します (example.com
をドメインに置き換えます)。
export DOMAIN="example.com" && \
cat << EOF | tee ingress/proxy.yaml
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: podinfo
namespace: projectcontour
annotations:
fluxcd.io/ignore: "false"
spec:
virtualhost:
fqdn: podinfo.${DOMAIN}
tls:
secretName: cert
includes:
- name: podinfo
namespace: demo
EOF
HTTPProxies には他の HTTPProxy オブジェクトを含めることができます。上記の構成には、デモ
名前空間の podinfo
HTTPProxy が含まれます。以下を参照してください。
$ cat podinfo/proxy.yaml
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: podinfo
namespace: demo
spec:
routes:
- services:
- name: podinfo
port: 9898
クロス名前空間インクルージョンを使用して、共有 TLS ワイルドカード証明書をロードできます。
それでは、Flux が証明書を取得してクラスターを同期するために、git 経由で変更を適用しましょう。
git add -A && \
git commit -m "expose podinfo" && \
git push origin master && \
fluxctl sync --k8s-fwd-ns fluxcd
仮想ホストに対して TLS が有効になっている場合、Contour はトラフィックを安全なインターフェイスにリダイレクトします。確認するには、(ドメインで) 次を実行します。
$ curl -vL podinfo.example.com
< HTTP/1.1 301 Moved Permanently
< location: https://podinfo.example.com/
できました。 最後に、少し高度なトピックであるプログレッシブ配信パラダイムを使用してトラフィックを新機能にルーティングする方法に進みます。
プログレッシブ配信
プログレッシブ配信は、Canary デプロイ、機能フラグ、A/B テストなどの高度なデプロイパターンを包括する用語です。これらの手法を使用して、アプリ開発者と SRE チームが広範囲をきめ細かく制御できるようにすることで、本番環境で新しいソフトウェアバージョンを導入するリスクを軽減します。
Flagger と Contour の HTTPProxy を一緒に使用して、ウェブアプリの Canary リリースと A/B テストを自動化できます。Flagger を使用する場合、podinfo
サービスとプロキシの定義を Canary の定義に置き換えます。Flagger は、Canary 仕様に基づいて、独自に Kubernetes ClusterIP サービスと Contour HTTPProxy を生成します。
アプリの新しいバージョンをデプロイすると、Flagger はトラフィックを徐々に Canary に移動し、同時にリクエストの成功率と平均応答時間を測定します。これらのメトリックは Envoy によって提供され、Prometheus によって収集されます。カスタムの Prometheus メトリック、受け入れテスト、負荷テストで Canary 分析を拡張し、アプリのリリースプロセスにおける検証プロセスを強化できます。
Flagger のお試しを希望する場合は、Contour プログレッシブ配信チュートリアルをご利用いただけます。