この記事は Gunosy Advent Calendar 2020 の 24日目の記事です。Gunosy Adsチームのリードエンジニアの会田です。Gunosy Adsチームでは昨年から配信システムのEKS移行などのシステムのインフラ改善に取り組んおり、この一年はEKSとKubernetes漬けの一年でした。
至近では、クラスタ内のトラフィックの管理のためにサービスメッシュとしてIstioを導入したので、Istioの導入における構成管理の話をしたいと思います。
Istio OperatorとTerraform
Istioのインストールは公式から、istioctl
による手動インストールと、Istio Operator
によるインストールの2つの方法が提供されています。istioctlはIstioのユーティリティコマンドで、Istioのインストールだけでなく、コンフィグの確認などで、Istioを使っていると何かとお世話になります。一方、Istio Operatorは手動インストールをする代わりに、Istioの構成管理を行ってくれるKubernetes Operatorです。Istio Operatorを使用するとKuberntesのCustom Resourceで、Istioのコンポーネントの構成管理ができます。
Gunosyではインフラの構成管理をTerraformで行っていて、Istioのインストールも可能な限りコードで管理したいので、istioctlによる手動インストールは避けて、Istio OperatorのインストールをTerraformで行うようにしました。
※作業時点では1.7.xが最新でした。現在の最新は1.8.xです。
公式のドキュメントのコマンドを参考に、次のようにistio-operatorのmanifestを生成して、k2tfでtfファイルに変換しました。
$ cd istio-1.7.3/
$ helm template manifests/charts/istio-operator \
--set hub=docker.io/istio \
--set tag=1.7.3 \
--set operatorNamespace=istio-operator \
--set watchedNamespaces=istio-system \
--set operator.resources.limits.cpu=64m \
--set operator.resources.limits.memory=256Mi \
--set operator.resources.requests.cpu=64m \
--set operator.resources.requests.memory=256Mi | k2tf > istio.tf
上記のコマンドを実行すると下のようなメッセージが出るので該当箇所については修正の必要があります。
8:43AM Warn | excluding attribute [kubernetes_deployment.spec.template.spec.container.security_context.capability] not found in Te
rraform schema field=Deployment.Spec.Template.Spec.Containers.SecurityContext.Capabilities name=istio_operator type=kubernetes_de
ployment
helm template
で生成したmanifestにはCRDが含まれていないので、上記のmanifestとは別にapplyする必要があります。
CRDとIstio Operatorをインストールすると、次のようなIstioOperatorのmanifestをapplyするとIstioの導入ができます。今回の導入ではIstio Gatewayを使用しないのでprofileを minimal
を指定しました。各profileでインストールされるコンポーネントはこちらから確認ができます。
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
name: default-istiocontrolplane
spec:
profile: minimal
kubernetes-provider
で管理できないmanifestの管理に kubenetes-provider-alpha
の仕様も検討しましたが、残念ながら次のようなエラーが terraform plan
で出てしまうので断念しました。おそらく kubernets-provider-alpha がplan時にCustom Resourceのバリデーションのために、KubernetesのAPIを叩くので、planの前にCRDの追加する必要があるためです。これは depends_on
で依存関係を指定しても解決しませんでした。
Error: rpc error: code = Unknown desc = no matches for install.istio.io/v1alpha1, Resource=IstioOperator
そこで kubernetes-provider
で管理できないmanifestは、次のように null_resource
と local-exec
を使用することにしました。 Istio Operatorのmanifestは環境毎に変更したい設定があるのでテンプレートを使用しています。
data "local_file" "istio_operator_crd" {
filename = "${path.module}/manifests/istio-operator-crd.yaml"
}
resource "null_resource" "istio_operator_crd" {
triggers = {
content_sha1 = filesha1(data.local_file.istio_operator_crd.filename)
}
provisioner "local-exec" {
command = "kubectl apply -f ${data.local_file.istio_operator_crd.filename}"
}
}
data "template_file" "default_istio_operator" {
template = "${file("${path.module}/manifests/istio-operator.yaml.tpl")}"
vars = {
cpu = local.istio_pilot_cpu_size[terraform.workspace]
memory = local.istio_pilot_memory_size[terraform.workspace]
}
}
resource "null_resource" "default_istio_operator" {
triggers = {
content_sha1 = sha1(data.template_file.default_istio_operator.rendered)
}
provisioner "local-exec" {
command = <<CMD
cat << EOF | kubectl apply -f -
${data.template_file.default_istio_operator.rendered}
EOF
CMD
}
depends_on = [
null_resource.istio_operator_crd,
kubernetes_namespace.istio_operator,
kubernetes_deployment.istio_operator,
]
}
namespaceのPodへのsidecar injectionの許可
Istioでトラフィックの管理を行いたい場合、対象のPodに istio-proxy
をサイドカーとして追加するように Sidecar Injection
をする必要があります。インジェクションには手動と自動の2つの方法があり、namespaceに対して istio-injection=enable
というラベルを追加すると、そのnamespaceのPodに自動でistio-proxyが追加されるようになります。
resource "kubernetes_namespace" "ads_api" {
metadata {
name = "ads-api"
labels = {
"istio-injection" = "enabled"
}
}
Istio Operatorの設定
上記の手順でIstio OperatorによるIstioの導入はできましたが、これらに加えていくつかの設定を追加しているので説明したいと思います。各設定の内容はこちらのドキュメントから確認ができます。
datadogをtracerに指定する
Gunosy AdsではAPMにDatadogを使用しているので、次のように修正してtracerの設定を追加しました。
profile: minimal
meshConfig:
enableTracing: true
values:
tracer: datadog
pilot:
traceSampling: 100.0
Istioのコンポーネントのリソース調整
ステージングやプロダクションなどの環境毎にistioのコンポーネントが使用するリソースの調整を行うために、次のような設定を追加しました。
components:
pilot:
k8s:
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 100m
memory: 256Mi
istio-proxy のlifecycleの変更
istio-proxyがSidecar InjectionされたPodでは、外部との通信がistio-proxyを経由するようになるので、MySQLなどPodの外のデータソースなどと通信するには istio-proxy
が起動している必要があります。アプリケーション側でistio-proxyの起動を確認するのは避けたいので、istio-proxyが起動してから他のコンテナが起動するように変更しました。
また、Podの停止時にデフォルトの挙動ではistio-proxyは他のコンテナを待たずに停止してしまうので、これはアプリケーションがgracefulに停止するために preStopに sleep
などを仕掛けている場合に都合が悪いので、istio-proxyが最後に停止するように変更しました。
上の2つの設定を反映したものが下の設定です。
values:
global:
proxy:
holdApplicationUntilProxyStarts: true
lifecycle:
preStop:
exec:
command:
- "/bin/sh"
- "-c"
- "while [ $(netstat -plunt | grep tcp | grep -v envoy | wc -l | xargs) -ne 0 ]; do sleep 1; done"
postStart:
exec:
command:
- pilot-agent
- wait
この設定にはこちらのサイトを参考にさせていただきました。
まとめ
この記事では、TerraformとIstio OpeartorでKubernetesクラスタ上のIstioのコンポーネントの構成管理をする方法について紹介しました。
今回は導入したてのため、アプリケーションへの導入の実例がご紹介できませんでしたが、知見が溜まったら、またご紹介させていただきたいと思います。