最初に、この記事にたどり着くような要件の場合は、高いセキュリティが必要な環境だと思っています。その場合はインターネット上のレジストリにあるイメージを使うことは本来推奨できるものでは無いと思います。この手順もかなり限定的な用途での利用となるかなと思います。
やりたいこと
プライベートなネットワークでもProxy経由でインターネット上のイメージを利用したい。
プライベートなネットワーク
方法として、原則プライベートで、Proxy経由でのみ外と通信するタイプのネットワークとなります。
プライベートサブネットに構築する、マネージドノードグループにProxyの設定を行いたいと思います。
図に表すと以下の通りです。
上の図を見ると、プライベートサブネットにエンドポイントが沢山あるのがわかります。要件によってはもっと必要です。
詳しくはこの辺りに記載があります。
調査
ここまで書いてきたような内容をGoogleで調べると、以下の記事にすぐ当たると思います。
ユーザーデータが投入された Amazon EKS ワーカーノードの HTTP プロキシ設定を自動化する
こちらは非マネージドノード対象ですが、プロキシの自動設定方法が書かれています。
UserData
を使うところを調整して使えばマネージドにも応用できるはずです。
環境準備
早速やってみます。
EKSコントロールプレーンのデプロイ
まず、環境をデプロイします。今回はeksctlを利用しています。
eksctl使ってEKSのコントロールプレーンをプライベートクラスタとしてデプロイします。説明の流れ上ノードの定義は抜いておきます。
EKS Fully-Private Cluster - eksctl
CLUSTER_NAME=your-private-cluster SUBNET_AZ_A=subnet-xxxxx SUBNET_AZ_C=subnet-xxxxx cat <<EOF > private-cluster.yml apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ${CLUSTER_NAME} region: ap-northeast-1 privateCluster: enabled: true additionalEndpointServices: - "autoscaling" - "logs" vpc: subnets: private: asia-northeast-1a: { id: ${SUBNET_AZ_A}} asia-northeast-1c: { id: ${SUBNET_AZ_C}} EOF
eksctlを以下のように実行します。
eksctl create cluster -f private-cluster.yml
※eksctlでPrivate Cluster作ると、最初パブリックで作って、パブリック&プライベートに変更してkubectl設定して、最後にプライベートに設定するので時間かかります。
作成後はSGなどは適宜調整します。
(必要に応じて) kubectlの設定
当初は作成者のみが権限持っているため、ロールに権限を割り当てておきます。
aws eks update-kubeconfig --name your-private-cluster
ADMIN_ROLE_ARN=arn:aws:iam::01234567891012:role/eks-admin cat <<EOF > role_map.yml apiVersion: v1 kind: ConfigMap metadata: name: aws-auth namespace: kube-system data: mapRoles: | - rolearn: ${ADMIN_ROLE_ARN} username: adminuser groups: - system:masters EOF kubectl apply -f role_map.yml
マネージドノードグループを追加
コンソール等からマネージドノードグループを追加します。細かい手順は省略します。
インターネット上のイメージからPodを起動するとエラーとなる
Docker Hubにあるnginxを起動してみると以下のようなエラーになります。
$ kubectl create deployment nginx-app --image=nginx deployment.apps/nginx-app created $ kubectl get po NAME READY STATUS RESTARTS AGE nginx-app-9964799-mq9cj 0/1 ErrImagePull 0 24s $ kubectl describe pod nginx-app-9964799-mq9cj # -- 省略 Warning Failed 14s (x2 over 44s) kubelet Failed to pull image "nginx": rpc error: code = Unknown desc = Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) # -- 省略
これはネットワーク設計上、当然の結果で、ECR側にあるイメージはVPCエンドポイント経由で問題無く利用できます。
マネージド型ノードグループにProxy設定
プライベートのEKSクラスタができたので、Proxy経由でイメージを取得する設定に入ります。
マネージド型ノードグループに起動テンプレートの UserData
を利用することで、Proxyを設定します。
起動テンプレートの設定(Cfn)
Cloudformationで起動テンプレートを作成します。ポイントは UserData
の部分なので、他の部分は適宜調整してください。
DockerのサービスにProxy設定を追加しています。
AWSTemplateFormatVersion: "2010-09-09" Parameters: ClusterIp: Type: String ProxyIP: Type: String ProxyPort: Type: Number SshKeyPairName: Type: String Resources: EKSManagedNodeInPrivateNetworkLaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: eks-managednodes-in-private-network LaunchTemplateData: InstanceType: m3.medium KeyName: !Ref SshKeyPairName UserData: !Base64 "Fn::Sub": | Content-Type: multipart/mixed; boundary="==BOUNDARY==" MIME-Version: 1.0 --==BOUNDARY== Content-Type: text/cloud-boothook; charset="us-ascii" #Set the proxy hostname and port PROXY=${ProxyIP}:${ProxyPort} MAC=$(curl -s http://169.254.169.254/latest/meta-data/mac/) VPC_CIDR=$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC/vpc-ipv4-cidr-blocks | xargs | tr ' ' ',') #Create the docker systemd directory mkdir -p /etc/systemd/system/docker.service.d #Configure docker with the proxy cloud-init-per instance docker_proxy_config tee <<EOF /etc/systemd/system/docker.service.d/http-proxy.conf >/dev/null [Service] Environment="HTTP_PROXY=http://$PROXY" Environment="HTTPS_PROXY=http://$PROXY" Environment="NO_PROXY=${ClusterIp},$VPC_CIDR,localhost,127.0.0.1,169.254.169.254,.internal,s3.amazonaws.com,.s3.ap-northeast-1.amazonaws.com,api.ecr.ap-northeast-1.amazonaws.com,dkr.ecr.ap-northeast-1.amazonaws.com,ec2.ap-northeast-1.amazonaws.com,ap-northeast-1.eks.amazonaws.com" EOF #Reload the daemon and restart docker to reflect proxy configuration at launch of instance cloud-init-per instance reload_daemon systemctl daemon-reload cloud-init-per instance enable_docker systemctl enable --now --no-block docker --==BOUNDARY==
Cloudformation実行時にPROXYのIP等を入れます。
マネージドノードグループの立ち上げ
マネージドノードを起動する際に、以下のように起動テンプレートを指定します。
起動テンプレートを指定したノードグループが立ち上がりました。
パブリックイメージを使ってPodの起動
今度起動した方のマネージドノードグループ上では、Docker Hubのイメージ使ってnginxが起動できました。
$ kubectl create deployment nginx-app --image=nginx deployment.apps/nginx-app created $ kubectl get po NAME READY STATUS RESTARTS AGE nginx-app-9964799-62xp5 1/1 Running 0 16s
さいごに
最初にも書いたのですが、Proxyで守っているような環境で、パブリックのレジストリからイメージを取るのはセキュリティ的に問題あるのでオススメしませんが、開発環境でのトラブルシュートなど限定的な場面で使える可能性があると思い書いておきました。