目次
- はじめに
- 参考文献
- 構築する環境
- 事前準備
- クライアントツールのインストール
- EC2でComputing Resourceをプロビジョニング
- 認証局(CA)のプロビジョニングとTLS証明書の生成
- 認証用kubeconfigの生成
- 暗号化の設定とキーの生成
- etcdの起動
- Kubernetesコントロールプレーンの起動
- ワーカーノードの起動
- リモートアクセス用のkubectl設定
- クラスタ内ネットワークの設定
- DNSクラスタアドオンの導入
- スモークテスト
- crictlを使用してワーカーノードのイメージ・ポッド・コンテナをチェックする
- 後片付け
- おわりに
はじめに
事業開発推進部の武井です。
「Kubernetes The Hard Way」をご存知でしょうか。
Kelsey Hightowerさんによって執筆された、Kubernetesを1から手作業で構築する手順がまとめられたチュートリアルです。
オリジナルのチュートリアルではGCPを使った構築手順が記載されていますが、私が普段使用する頻度の高いAWSでの再現を試みてみました。
参考文献
AWS環境に本チュートリアルを構成するにあたり、以下の記事を参考にしています。
https://github.com/prabhatsharma/kubernetes-the-hard-way-aws/blob/master/README.md
https://qiita.com/rabiho/items/1e7423909701a44a69af
構築する環境
Kubernetes The Hard Wayでは、コンポーネント間の暗号化とRBAC認証ができる、可用性の高いクラスタを構築します。
使用するコンポーネントとそのバージョン一覧は下記の通りです。
- Kubernetes v1.24.0
- containerd v1.16.6
- coredns v1.19.3
- cni v1.1.1
- etcd v3.5.4
01-事前準備
Amazon Web Service
このチュートリアルではAmazon Web Service(以下AWS)を利用して、kubernetesクラスターを立ち上げます。今回使用するリソースはAWSの無料枠を超えるので、チュートリアル終了後には作成したリソースをクリーンアップし、不要なコストが発生しないよう注意してください。
AWS CLIのインストール
AWS CLIをインストールし、必要な設定を行います。 詳細手順に関してはAWSの公式ドキュメントを参照ください。
インストール完了後、以下のコマンドでAWS CLIが有効であることを確認します。
デフォルトリージョンの設定
このチュートリアルで使用するデフォルトリージョンを設定します。
AWS_REGION=ap-northeast-1aws configure set default.region $AWS_REGION
tmuxを使ったパラレルなコマンド実行
オリジナルのチュートリアルでも推奨の設定として記載されています。
この手順をスキップしてもKubernetesクラスタの動作に影響はありません。
kubernetes-the-hard-way/01-prerequisites.md at master · kelseyhightower/kubernetes-the-hard-way Bootstrap Kubernetes the hard way on Google Cloud Platform. N github.com
作業用ディレクトリの作成
本チュートリアルでは、多くのファイル生成や転送の処理を行います。
また、リモート接続のためのキーペアの払い出しも行います。
ファイル管理の観点から、予め作業用ディレクトリを作成し、そこをチュートリアル中のカレントディレクトリとすることを推奨します。
02-クライアントツールのインストール
このセクションではcfssl, cfssljson,kubectlのインストールを行います。
CFSSLとCFSSLJSONのインストール
cvfsslとcfssljsonはPKI環境の構築とTLSの証明書発行に使用するツールです。
OS X(Mac OS)
curl -o cfssl https://pkg.cfssl.org/R1.2/cfssl_darwin-amd64
curl -o cfssljson https://pkg.cfssl.org/R1.2/cfssljson_darwin-amd64
chmod +x cfssl cfssljson
sudo mv cfssl cfssljson /usr/local/bin/
OS Xを使用しpre-buildでインストールしようとした場合、問題が生じる場合があります
その場合はHomebrewを使用してインストールを行なってください。
インストールのコマンドは以下です。
brew install cfssl
Linux
wget -q --show-progress --https-only --timestamping \
https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 \
https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64
sudo mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
確認
cfssl version
動作確認済みのバージョンは以下です。
Version: 1.6.1
Runtime: go1.17.2
kubectlのインストール
kubectlはKubernetesが持つAPI Serverとの通信に使用されるコマンドラインツールです。今回はv1.24.0を使用しています。
OS X
curl -o kubectl https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/darwin/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
Linux
wget https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/linux/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
確認
kubectlバージョン1.24.0がインストールされていることを確認します。
kubectl version --client
出力例
Client Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.0", GitCommit:"4ce5a8954017644c5420bae81d72b09b735c21f0", GitTreeState:"clean", BuildDate:"2022-05-03T13:46:05Z", GoVersion:"go1.18.1", Compiler:"gc", Platform:"darwin/amd64"}Kustomize Version: v4.5.4
03-EC2でComputing Resourceをプロビジョニング
Kubernetesはクラスタを管理するためのControll Planeと、コンテナを実行するためのKubernetes Nodeで構成されており、それらをホストするためのこのユーティングリソースが必要です。
このセクションでは、単一のコンピューティングゾーンで安全で可用性の高いKubernetesクラスターを実行するために必要なコンピューティングリソースをプロビジョニングします。
ネットワーク
Kubernetesのネットワークモデルは、コンテナとノードが相互に通信できるフラットネットワークを想定しています。これが正しく構成されていない場合、ネットワークポリシーによりコンテナ間や外部ネットワークへの通信が制限される可能性があります。尚、Network Policyの設定はこのチュートリアルの範囲外です。
仮想プライベートクラウド(VPC)
このステップでは、Kubernetesクラスタをホストするために専用の仮想プライベートクラウド(VPC)やネットワークをセットアップします。
今回はkubernetes-the-hard-wayというValueを持ったVPCを作成します。
VPCの作成
VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --output text --query 'Vpc.VpcId')
aws ec2 create-tags --resources ${VPC_ID} --tags Key=Name,Value=kubernetes-the-hard-way
aws ec2 modify-vpc-attribute --vpc-id ${VPC_ID} --enable-dns-support '{"Value": true}'
aws ec2 modify-vpc-attribute --vpc-id ${VPC_ID} --enable-dns-hostnames '{"Value": true}'
Subnetの作成
サブネットは、Kubernetesクラスタ内の各ノードにプライベートIPアドレスを割り当てるためのリソースです。IPレンジに関しては十分な範囲を持たせてください。尚、このチュートリアルでは10.0.1.0/24のサブネットを使用しており、最大254のコンピューティングインスタンスをホストできます。
以下はkubernetes-the-hard-wayのVPCにkubernetesサブネットをプロビジョニングしています。
SUBNET_ID=$(aws ec2 create-subnet \
--vpc-id ${VPC_ID} \
--cidr-block 10.0.1.0/24 \
--output text --query 'Subnet.SubnetId')
aws ec2 create-tags --resources ${SUBNET_ID} --tags Key=Name,Value=kubernetes
Internet Gatewayの作成
インターネットゲートウェイはKubernetesのコントローラが外部からAPIのエンドポイントとなるために必要な構成です。
以下はkubernetes-the-hard-wayのVPCにkubernetes Internet Gatewayを作成しています。
INTERNET_GATEWAY_ID=$(aws ec2 create-internet-gateway --output text --query 'InternetGateway.InternetGatewayId')
aws ec2 create-tags --resources ${INTERNET_GATEWAY_ID} --tags Key=Name,Value=kubernetes
aws ec2 attach-internet-gateway --internet-gateway-id ${INTERNET_GATEWAY_ID} --vpc-id ${VPC_ID}
Route Tablesの作成
ルートテーブルは、VPC内の仮想ルータが参照するルーティングテーブルです。以下はkubernetes-the-hard-wayのVPCに0.0.0.0/0のデフォルトルートを設定しています。
ROUTE_TABLE_ID=$(aws ec2 create-route-table --vpc-id ${VPC_ID} --output text --query 'RouteTable.RouteTableId')
aws ec2 create-tags --resources ${ROUTE_TABLE_ID} --tags Key=Name,Value=kubernetes
aws ec2 associate-route-table --route-table-id ${ROUTE_TABLE_ID} --subnet-id ${SUBNET_ID}
aws ec2 create-route --route-table-id ${ROUTE_TABLE_ID} --destination-cidr-block 0.0.0.0/0 --gateway-id ${INTERNET_GATEWAY_ID}
Security Groupsの作成
セキュリティグループはVPC内の仮想ファイアウォールとして機能します。
以下はKubernetesクラスタ間の内部通信と外部SSH,ICMPおよびHTTPSを許可するセキュリティポリシーを記載しています。
SECURITY_GROUP_ID=$(aws ec2 create-security-group \
--group-name kubernetes \
--description "Kubernetes security group" \
--vpc-id ${VPC_ID} \
--output text --query 'GroupId')
aws ec2 create-tags --resources ${SECURITY_GROUP_ID} --tags Key=Name,Value=kubernetes
aws ec2 authorize-security-group-ingress --group-id ${SECURITY_GROUP_ID} --protocol all --cidr 10.0.0.0/16
aws ec2 authorize-security-group-ingress --group-id ${SECURITY_GROUP_ID} --protocol all --cidr 10.200.0.0/16
aws ec2 authorize-security-group-ingress --group-id ${SECURITY_GROUP_ID} --protocol tcp --port 22 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id ${SECURITY_GROUP_ID} --protocol tcp --port 6443 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id ${SECURITY_GROUP_ID} --protocol tcp --port 443 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id ${SECURITY_GROUP_ID} --protocol icmp --port -1 --cidr 0.0.0.0/0
Kubernetes Public Accessの設定
Kubernetes APIサーバのエンドポイントとして割り当てるIPアドレスを設定します。
LOAD_BALANCER_ARN=$(aws elbv2 create-load-balancer \
--name kubernetes \
--subnets ${SUBNET_ID} \
--scheme internet-facing \
--type network \
--output text --query 'LoadBalancers[].LoadBalancerArn')
TARGET_GROUP_ARN=$(aws elbv2 create-target-group \
--name kubernetes \
--protocol TCP \
--port 6443 \
--vpc-id ${VPC_ID} \
--target-type ip \
--output text --query 'TargetGroups[].TargetGroupArn')
aws elbv2 register-targets --target-group-arn ${TARGET_GROUP_ARN} --targets Id=10.0.1.1{0,1,2}
aws elbv2 create-listener \
--load-balancer-arn ${LOAD_BALANCER_ARN} \
--protocol TCP \
--port 443 \
--default-actions Type=forward,TargetGroupArn=${TARGET_GROUP_ARN} \
--output text --query 'Listeners[].ListenerArn'
インスタンス
このステップでは、KubernetesクラスタのホストとなるVMをプロビジョニングします。
Instance Imageの定義
利用するインスタンスイメージを定義します。
今回はパブリックとして公開しているubuntuのAMIを指定しています。
IMAGE_ID=$(aws ec2 describe-images --owners 099720109477 \
--output json \
--filters \
'Name=root-device-type,Values=ebs' \
'Name=architecture,Values=x86_64' \
'Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*' \
| jq -r '.Images|sort_by(.Name)[-1]|.ImageId')
jqコマンドが入っていない場合は以下のコマンドでインストールを行います。
brew install jq
SSH Key Pairの作成
EC2インスタンスにSSH接続するためのKey Pairを作成します。
aws ec2 create-key-pair --key-name kubernetes --output text --query 'KeyMaterial' > kubernetes.id_rsa
chmod 600 kubernetes.id_rsa
Kubernetes Control Plane用ホストの立ち上げ
Amazon EC2で、Kubernetesコントローラノードのホストとなる仮想マシンを作成します。今回は t3.microインスタンスを使用し、3台の仮想マシンを立ち上げます。
for i in 0 1 2; do
instance_id=$(aws ec2 run-instances \
--associate-public-ip-address \
--image-id ${IMAGE_ID} \
--count 1 \
--key-name kubernetes \
--security-group-ids ${SECURITY_GROUP_ID} \
--instance-type t3.micro \
--private-ip-address 10.0.1.1${i} \
--user-data "name=controller-${i}" \
--subnet-id ${SUBNET_ID} \
--block-device-mappings='{"DeviceName": "/dev/sda1", "Ebs": { "VolumeSize": 50 }, "NoDevice": "" }' \
--output text --query 'Instances[].InstanceId')
aws ec2 modify-instance-attribute --instance-id ${instance_id} --no-source-dest-check
aws ec2 create-tags --resources ${instance_id} --tags "Key=Name,Value=controller-${i}"
echo "controller-${i} created "
done
Kubernetes Worker Node用ホストの立ち上げ
Amazon EC2でKubernetes Worker Nodeのホストとなる仮想マシンを作成します。今回は t3.microインスタンスを使用し、3台の仮想マシンを立ち上げます。
Kubernetes Worker Nodeはコンテナアプリケーションが展開、実行される場所であるため実際のサイジングは非常に重要です。アプリケーションの要件に応じたリソース計算が求められます。
for i in 0 1 2; do
instance_id=$(aws ec2 run-instances \
--associate-public-ip-address \
--image-id ${IMAGE_ID} \
--count 1 \
--key-name kubernetes \
--security-group-ids ${SECURITY_GROUP_ID} \
--instance-type t3.micro \
--private-ip-address 10.0.1.2${i} \
--user-data "name=worker-${i}|pod-cidr=10.200.${i}.0/24" \
--subnet-id ${SUBNET_ID} \
--block-device-mappings='{"DeviceName": "/dev/sda1", "Ebs": { "VolumeSize": 50 }, "NoDevice": "" }' \
--output text --query 'Instances[].InstanceId')
aws ec2 modify-instance-attribute --instance-id ${instance_id} --no-source-dest-check
aws ec2 create-tags --resources ${instance_id} --tags "Key=Name,Value=worker-${i}"
echo "worker-${i} created"
done
04-認証局(CA)のプロビジョニングとTLS証明書の生成
このセクションでは、CloudFlareのPKIツールキットである cfsslを使用してPKI基盤をプロビジョニングします。PKI基盤を利用して認証局を作り、以下を生成します。
- admin用のTLS証明書
- 各コンポーネントのTLS証明書
- etcd
- kube-apiserver
- kube-controller-manager
- kube-scheduler
- kubelet
- kube-proxy
各コンポーネントの役割は以下を参照ください。
Kubernetes ComponentsKubernetes Components A Kubernetes cluster consists of the components that represen kubernetes.io
認証局(CA)の立ち上げ
このステップでは、TLS証明書を生成するための認証局(CA)をプロビジョニングします。
CA設定ファイル、CA自身の証明書、および秘密鍵を生成します。
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"kubernetes": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "8760h"
}
}
}
}
EOF
cat > ca-csr.json <<EOF
{
"CN": "Kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "CA",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
以下のファイルが生成されます。
ca-key.pem
ca.pem
クライアントとサーバーの証明書発行
このステップでは、各Kubernetesコンポーネントで使うクライアント証明書とサーバー証明書、adminユーザー用のクライアント証明書を発行します。
Admin用クライアント証明書の発行
admin用のクライアント証明書と秘密鍵を生成します。
cat > admin-csr.json <<EOF
{
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
admin-csr.json | cfssljson -bare admin
以下のファイルが生成されます。
admin-key.pem
admin.pem
Kubelet用クライアント証明書の発行
Kubernetesは、Node Authorizerと呼ばれる特別な用途向けの認可モードを利用します。主にKubeletsからのAPIリクエストの認証の役割を担いますが、Node Authorizerの認可のためにはsystem:nodes groupの中のsystem:node:<nodeName>というユーザー名で認証されるように証明書を作成しなければなりません。詳細は以下をご覧ください。
Using Node AuthorizationUsing Node Authorization Node authorization is a special-purpose authorization mode th kubernetes.io
このステップでは、KubernetesワーカーノードごとにNode Authorizerの要求を満たす証明書と秘密鍵を発行します。
for i in 0 1 2; do
instance="worker-${i}"
instance_hostname="ip-10-0-1-2${i}"
cat > ${instance}-csr.json <<EOF
{
"CN": "system:node:${instance_hostname}",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:nodes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
external_ip=$(aws ec2 describe-instances --filters \
"Name=tag:Name,Values=${instance}" \
"Name=instance-state-name,Values=running" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
internal_ip=$(aws ec2 describe-instances --filters \
"Name=tag:Name,Values=${instance}" \
"Name=instance-state-name,Values=running" \
--output text --query 'Reservations[].Instances[].PrivateIpAddress')
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname=${instance_hostname},${external_ip},${internal_ip} \
-profile=kubernetes \
worker-${i}-csr.json | cfssljson -bare worker-${i}
done
以下のファイルが生成されます。
worker-0-key.pem
worker-0.pem
worker-1-key.pem
worker-1.pem
worker-2-key.pem
worker-2.pem
kube-contorller-manager用 クライアント証明書の発行
kube-controller-managerのクライアント証明書と秘密鍵を発行します。
cat > kube-controller-manager-csr.json <<EOF
{
"CN": "system:kube-controller-manager",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:kube-controller-manager",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
以下のファイルが生成されます。
kube-controller-manager-key.pem
kube-controller-manager.pem
kube-proxy 用 クライアント証明書の発行
kube-proxyのクライアント証明書と秘密鍵を発行します。
cat > kube-proxy-csr.json <<EOF
{
"CN": "system:kube-proxy",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:node-proxier",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-proxy-csr.json | cfssljson -bare kube-proxy
以下のファイルが生成されます。
kube-proxy-key.pem
kube-proxy.pem
kube-scheduler用 クライアント証明書の発行
kube-scheduler クライアント用の証明書と秘密鍵を発行します。
cat > kube-scheduler-csr.json <<EOF
{
"CN": "system:kube-scheduler",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:kube-scheduler",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
kube-scheduler-csr.json | cfssljson -bare kube-scheduler
以下のファイルが生成されます。
kube-scheduler-key.pem
kube-scheduler.pem
Kubernetes API サーバー用証明書の発行
kubernetes-the-hard-way のstatic IPアドレスは、Kubernetes API サーバーの証明書のSAN(subject alternative names)のリストに含める必要があります。
外部のクライアントでも証明書を使った検証を行うための設定です。
Kubernetes API サーバーの証明書と秘密鍵を生成します。
KUBERNETES_HOSTNAMES=kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.svc.cluster.local
cat > kubernetes-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-hostname=10.32.0.1,10.0.1.10,10.0.1.11,10.0.1.12,${KUBERNETES_PUBLIC_ADDRESS},127.0.0.1,${KUBERNETES_HOSTNAMES} \
-profile=kubernetes \
kubernetes-csr.json | cfssljson -bare kubernetes
以下のファイルが生成されます。
kubernetes-key.pem
kubernetes.pem
サービスアカウントのキーペアを発行
サービスアカウントの管理のドキュメントにあるように、Kubernetes Controller Managerは、サービスアカウントのトークンの生成と署名をするためにキーペアを使用します。
service-account の証明書と秘密鍵を発行します。
cat > service-account-csr.json <<EOF
{
"CN": "service-accounts",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "Kubernetes",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}
EOF
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=kubernetes \
service-account-csr.json | cfssljson -bare service-account
以下のファイルが生成されます。
service-account-key.pem
service-account.pem
クライアント証明書とサーバー証明書の配布
証明書と秘密鍵をコピーし、各ワーカーインスタンスに配置します。
配置対象は以下です。
- CA証明書
- APIサーバの証明書
- ワーカーノードの証明書と秘密鍵
for instance in worker-0 worker-1 worker-2; do
external_ip=$(aws ec2 describe-instances --filters \
"Name=tag:Name,Values=${instance}" \
"Name=instance-state-name,Values=running" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
scp -i kubernetes.id_rsa ca.pem ${instance}-key.pem ${instance}.pem ubuntu@${external_ip}:~/
done
接続処理を続けて良いか聞かれた場合はyesを入力します。
Are you sure you want to continue connecting (yes/no/[fingerprint])?
転送に成功すると以下のような出力結果を得られます。
ca.pem 100% 1318 32.0KB/s 00:00
worker-1-key.pem 100% 1675 72.6KB/s 00:00
worker-1.pem 100% 1509 40.6KB/s 00:00
上記はワーカーインスタンスの台数分繰り返し処理されます。コントローラーインスタンスにも同様に配置します。
配置対象は以下です。
- CA証明書
- APIサーバの証明書と秘密鍵
- サービスアカウント払い出し用キーペア
for instance in controller-0 controller-1 controller-2; do
external_ip=$(aws ec2 describe-instances --filters \
"Name=tag:Name,Values=${instance}" \
"Name=instance-state-name,Values=running" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
scp -i kubernetes.id_rsa \
ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
service-account-key.pem service-account.pem ubuntu@${external_ip}:~/
done
接続処理を続けて良いか聞かれた場合は’yes’を入力します。
Are you sure you want to continue connecting (yes/no/[fingerprint])?
転送に成功すると以下のような出力結果を得られます。
ca.pem 100% 1318 59.2KB/s 00:00
ca-key.pem 100% 1679 42.0KB/s 00:00
kubernetes-key.pem 100% 1675 73.4KB/s 00:00
kubernetes.pem 100% 1598 44.6KB/s 00:00
service-account-key.pem 100% 1675 72.0KB/s 00:00
service-account.pem 100% 1440 65.8KB/s 00:00
尚、下記コンポーネントのクライアント証明書は次の手順で使用します。
- kube-proxy
- kube-controller-manager
- kube-scheduler
- kubelet
05-認証用kubeconfigの生成
このセクションでは、Kubernetes APIサーバーがKubernetesのクライアントを配置、認証できるようにするためのkubeconfig(Kubernetes構成ファイル)を生成します。生成するファイルは以下です。
- conttoller-manager
- kubelet
- kube-proxy
- scheduler
- adminユーザー用のkubeconfig
KubernetesのPublic DNSアドレスを取得
各kubeconfigはKubernetes APIサーバと接続できることが要求されます。
高可用性を実現するために、Kubernetes APIサーバの前に設置されている外部ロードバランサーのIPアドレスを使用します。
kubernetes-the-hard-wayのDNSアドレスを取得します。
KUBERNETES_PUBLIC_ADDRESS=$(aws elbv2 describe-load-balancers \
--load-balancer-arns ${LOAD_BALANCER_ARN} \
--output text --query 'LoadBalancers[0].DNSName')
echo ${KUBERNETES_PUBLIC_ADDRESS}
kubelet用kubeconfigsの生成
kubelet用のkubeconfigファイルを生成するときは、kubeletのノード名と同じクライアント証明書を使用する必要があります。これにより、kubeletがKubernetesのNode Authorizerによって認可されるようになります。
ワーカーノード毎にkubeconfigを生成します。
for instance in worker-0 worker-1 worker-2; do
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://${KUBERNETES_PUBLIC_ADDRESS}:443 \
--kubeconfig=${instance}.kubeconfig
kubectl config set-credentials system:node:${instance} \
--client-certificate=${instance}.pem \
--client-key=${instance}-key.pem \
--embed-certs=true \
--kubeconfig=${instance}.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:node:${instance} \
--kubeconfig=${instance}.kubeconfig
kubectl config use-context default --kubeconfig=${instance}.kubeconfig
done
以下のファイルが生成されます。
worker-0.kubeconfig
worker-1.kubeconfig
worker-2.kubeconfig
kube-proxy用kubeconfigの生成
kube-proxyのkubeconfigも生成します。
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://${KUBERNETES_PUBLIC_ADDRESS}:443 \
--kubeconfig=kube-proxy.kubeconfig
kubectl config set-credentials system:kube-proxy \
--client-certificate=kube-proxy.pem \
--client-key=kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=kube-proxy.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:kube-proxy \
--kubeconfig=kube-proxy.kubeconfig
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
以下のファイルが生成されます。
kube-proxy.kubeconfig
kube-controller-manager用kubeconfigの生成
kube-controller-managerのkubeconfigを生成します。
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:6443 \
--kubeconfig=kube-controller-manager.kubeconfig
kubectl config set-credentials system:kube-controller-manager \
--client-certificate=kube-controller-manager.pem \
--client-key=kube-controller-manager-key.pem \
--embed-certs=true \
--kubeconfig=kube-controller-manager.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:kube-controller-manager \
--kubeconfig=kube-controller-manager.kubeconfig
kubectl config use-context default --kubeconfig=kube-controller-manager.kubeconfig
以下のファイルが生成されます。
kube-controller-manager.kubeconfig
kube-scheduler用kubeconfigの生成
kube-schedulerのkubeconfigを生成します。
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:6443 \
--kubeconfig=kube-scheduler.kubeconfig
kubectl config set-credentials system:kube-scheduler \
--client-certificate=kube-scheduler.pem \
--client-key=kube-scheduler-key.pem \
--embed-certs=true \
--kubeconfig=kube-scheduler.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:kube-scheduler \
--kubeconfig=kube-scheduler.kubeconfig
kubectl config use-context default --kubeconfig=kube-scheduler.kubeconfig
以下のファイルが生成されます。
kube-scheduler.kubeconfig
adminユーザー用kubeconfigの生成
adminユーザーのkubeconfigを生成します。
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://127.0.0.1:6443 \
--kubeconfig=admin.kubeconfig
kubectl config set-credentials admin \
--client-certificate=admin.pem \
--client-key=admin-key.pem \
--embed-certs=true \
--kubeconfig=admin.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=admin \
--kubeconfig=admin.kubeconfig
kubectl config use-context default --kubeconfig=admin.kubeconfig
以下のファイルが生成されます。
admin.kubeconfig
kubeconfigの配布
kubeletとkube-proxyのkubecnofigをコピーし、各ワーカーノードに配置します。
for instance in worker-0 worker-1 worker-2; do
external_ip=$(aws ec2 describe-instances --filters \
"Name=tag:Name,Values=${instance}" \
"Name=instance-state-name,Values=running" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
scp -i kubernetes.id_rsa \
${instance}.kubeconfig kube-proxy.kubeconfig ubuntu@${external_ip}:~/
done
出力例
worker-0.kubeconfig 100% 6449 260.8KB/s 00:00
kube-proxy.kubeconfig 100% 6371 261.1KB/s 00:00
worker-1.kubeconfig 100% 6449 273.1KB/s 00:00
kube-proxy.kubeconfig 100% 6371 268.2KB/s 00:00
worker-2.kubeconfig 100% 6449 265.6KB/s 00:00
kube-proxy.kubeconfig 100% 6371 287.2KB/s 00:00
kube-controller-managerとkube-schedulerのkubeconfigをコピーし、各コントローラーノードに配置します。
for instance in controller-0 controller-1 controller-2; do
external_ip=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=${instance}" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
scp -i kubernetes.id_rsa \
admin.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig ubuntu@${external_ip}:~/
done
出力例
admin.kubeconfig 100% 6265 255.2KB/s 00:00
kube-controller-manager.kubeconfig 100% 6387 51.6KB/s 00:00
kube-scheduler.kubeconfig 100% 6241 249.1KB/s 00:00
admin.kubeconfig 100% 6265 276.1KB/s 00:00
kube-controller-manager.kubeconfig 100% 6387 271.4KB/s 00:00
kube-scheduler.kubeconfig 100% 6241 122.2KB/s 00:00
admin.kubeconfig 100% 6265 278.5KB/s 00:00
kube-controller-manager.kubeconfig 100% 6387 127.7KB/s 00:00
kube-scheduler.kubeconfig 100% 6241 276.7KB/s 00:00
06-暗号化の設定とキーの生成
Kubernetesは、クラスタの状態、アプリケーションの設定、秘匿情報などを含むさまざまなデータが格納されます。そのデータを守るために、Kubernetesはクラスタ内で保持しているデータを暗号化する機能が提供されています。このステップでは、Kubernetes Secretsの暗号化に合わせた暗号化鍵と暗号化の設定ファイルを生成します。
暗号化鍵
暗号化に使用する鍵を作成します。
ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
暗号化の設定ファイル
暗号化の設定のためのencryption-config.yamlを生成します。
cat > encryption-config.yaml <<EOF
kind: EncryptionConfig
apiVersion: v1
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: ${ENCRYPTION_KEY}
- identity: {}
EOF
encryption-config.yamlをコピーし、各コントローラーノードに配置します。
for instance in controller-0 controller-1 controller-2; do
external_ip=$(aws ec2 describe-instances --filters \
"Name=tag:Name,Values=${instance}" \
"Name=instance-state-name,Values=running" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
scp -i kubernetes.id_rsa encryption-config.yaml ubuntu@${external_ip}:~/
done
出力例
encryption-config.yaml 100% 240 10.4KB/s 00:00
encryption-config.yaml 100% 240 5.2KB/s 00:00
encryption-config.yaml 100% 240 4.9KB/s 00:00
07-etcdの起動
Kubernetesの各コンポーネントはステートレスになっており、クラスタの状態は全てetcdに格納され管理されています。そのため、etcdはKubernetesにおいて重要なコンポーネントであると位置付けられており、多くの場合はetcdの高い可用性を担保することが求められます。このセクションでは、3ノードのetcdクラスタを構築して、高可用性と安全な外部アクセスを実現します。
準備
このステップのコマンドは、controller-0、controller-1、controller-2の各コントローラインスタンスで実行する必要があります。以下の様にsshコマンドを使用して各コントローラーノードにログインしてください。
for instance in controller-0 controller-1 controller-2; do
external_ip=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=${instance}" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
echo ssh -i kubernetes.id_rsa ubuntu@$external_ip
done
ここからの手順は、直前のコマンドによって出力されたそれぞれのIPアドレスにssh接続して行います。
(3台のインスタンス全てで同じコマンドを実行する必要があります)
tmuxを使えば、容易に複数のインスタンスで同時にコマンドを実行できます。詳細はこちらをご覧ください。
etcdのクラスタメンバーの起動
ここからの手順は各コントローラーインスタンスで行います
etcdのダウンロードとインストール
etcdのバイナリをgithubからダウンロードします。
wget -q --show-progress --https-only --timestamping \
"https://github.com/etcd-io/etcd/releases/download/v3.5.4/etcd-v3.5.4-linux-amd64.tar.gz"
ダウンロードしたファイルを展開してetcdサーバーとetcdctlのコマンドラインユーティリティを抽出します。
tar -xvf etcd-v3.5.4-linux-amd64.tar.gz
sudo mv etcd-v3.5.4-linux-amd64/etcd* /usr/local/bin/
etcdサーバーの設定を行います。
sudo mkdir -p /etc/etcd /var/lib/etcd
sudo chmod 700 /var/lib/etcd
sudo cp ca.pem kubernetes-key.pem kubernetes.pem /etc/etcd/
インスタンスの内部IPアドレスは、クライアントのリクエストを受け付けて、etcdクラスタ間で通信するために使います。
現在のEC2インスタンスの内部IPアドレスを取得します。
INTERNAL_IP=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)
echo ${INTERNAL_IP}
各etcdのメンバーは、etcdクラスター内で名前はユニークにする必要があります。このチュートリアルでは、現在使用しているEC2インスタンスのホスト名をetcdの名前として設定します。
ETCD_NAME=$(curl -s http://169.254.169.254/latest/user-data/ \
| tr "|" "\n" | grep "^name" | cut -d"=" -f2)
echo "${ETCD_NAME}"
etcd.serviceとしてsystemdのユニットファイルを作成します。
cat <<EOF | sudo tee /etc/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.com/coreos
[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \\
--name ${ETCD_NAME} \\
--cert-file=/etc/etcd/kubernetes.pem \\
--key-file=/etc/etcd/kubernetes-key.pem \\
--peer-cert-file=/etc/etcd/kubernetes.pem \\
--peer-key-file=/etc/etcd/kubernetes-key.pem \\
--trusted-ca-file=/etc/etcd/ca.pem \\
--peer-trusted-ca-file=/etc/etcd/ca.pem \\
--peer-client-cert-auth \\
--client-cert-auth \\
--initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
--listen-peer-urls https://${INTERNAL_IP}:2380 \\
--listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
--advertise-client-urls https://${INTERNAL_IP}:2379 \\
--initial-cluster-token etcd-cluster-0 \\
--initial-cluster controller-0=https://10.0.1.10:2380,controller-1=https://10.0.1.11:2380,controller-2=https://10.0.1.12:2380 \\
--initial-cluster-state new \\
--data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
etcdサーバーの起動
sudo systemctl daemon-reload
sudo systemctl enable etcd
sudo systemctl start etcd
ここまでの手順を、各コントローラーノードcontroller-0,controller-1,controller-2で実行してください。
確認
etcdのクラスタメンバーを一覧表示します。
sudo ETCDCTL_API=3 etcdctl member list \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/ca.pem \
--cert=/etc/etcd/kubernetes.pem \
--key=/etc/etcd/kubernetes-key.pem
出力例
3a57933972cb5131, started, controller-2, https://10.240.0.12:2380, https://10.240.0.12:2379, false
f98dc20bce6225a0, started, controller-0, https://10.240.0.10:2380, https://10.240.0.10:2379, false
ffed16798470cab5, started, controller-1, https://10.240.0.11:2380, https://10.240.0.11:2379, false
08-Kubernetesコントロールプレーンの起動
このセクションでは、3つのインスタンスを使って可用性の高いKubernetesコントロールプレーンを作成します。合わせて、Kubernetes API Serverを外部クライアントに公開する外部ロードバランサーも作成します。
各ノードに、Kubernetes API Server、Scheduler、およびController Managerのコンポーネントをインストールします。
事前確認
各コントローラノードにログインする前に、自身の端末でKubernetesクラスタの外部公開用のFQDNを確認する必要があります。
以下のコマンドを実行し、FQDNを確認します。
echo ${KUBERNETES_PUBLIC_ADDRESS}
後続のステップで使用するため、出力結果をメモしてください。
作業対象
前のセクションと同様、このセクションでもcontroller-0,controller-1,controller-2の各コントローラインスタンスで実行する必要があります。全てのコントローラーノードにsshコマンドでログインしてコマンドを実行します。既に各コントローラーノードにログインしている状態であれば、次の「Kubernetesコントロールプレーンのプロビジョニング」に飛んでください
for instance in controller-0 controller-1 controller-2; do
external_ip=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=${instance}" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
echo ssh -i kubernetes.id_rsa ubuntu@$external_ip
done
ここからの手順は、直前のコマンドによって出力されたそれぞれのIPアドレスにssh接続して行います。
(3台のインスタンス全てで同じコマンドを実行する必要があります)
tmuxを使えば、容易に複数のインスタンスで同時にコマンドを実行できます。詳細はこちらをご覧ください。
Kubernetesコントロールプレーンのプロビジョニング
Kubernetesのconfigファイルを配置するためのディレクトリを作成します。
sudo mkdir -p /etc/kubernetes/config
KubernetesコントローラーのバイナリのDLとインストール
Kubernetesの公式のリリースバイナリをダウンロードします
wget -q --show-progress --https-only --timestamping \
"https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/linux/amd64/kube-apiserver" \
"https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/linux/amd64/kube-controller-manager" \
"https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/linux/amd64/kube-scheduler" \
"https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/linux/amd64/kubectl"
ダウンロードしたバイナリを移動させます。
chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/
KubernetesAPIサーバーの設定
sudo mkdir -p /var/lib/kubernetes/
sudo mv ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
service-account-key.pem service-account.pem \
encryption-config.yaml /var/lib/kubernetes/
APIサーバーをクラスターのメンバーに知らせるための設定として、インスタンスの内部IPアドレスを使います。現在のEC2インスタンスの内部IPアドレスを取得します。
INTERNAL_IP=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)
echo ${INTERNAL_IP}
kube-apiserver.serviceのsystemdのユニットファイルを生成します。
KUBERNETES_PUBLIC_ADDRESS=[事前確認の出力結果](#事前確認)
cat <<EOF | sudo tee /etc/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
--advertise-address=${INTERNAL_IP} \\
--allow-privileged=true \\
--apiserver-count=3 \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/var/log/audit.log \\
--authorization-mode=Node,RBAC \\
--bind-address=0.0.0.0 \\
--client-ca-file=/var/lib/kubernetes/ca.pem \\
--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
--etcd-cafile=/var/lib/kubernetes/ca.pem \\
--etcd-certfile=/var/lib/kubernetes/kubernetes.pem \\
--etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \\
--etcd-servers=https://10.0.1.10:2379,https://10.0.1.11:2379,https://10.0.1.12:2379 \\
--event-ttl=1h \\
--encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
--kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \\
--kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \\
--kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \\
--runtime-config='api/all=true' \\
--service-account-key-file=/var/lib/kubernetes/service-account.pem \\
--service-account-signing-key-file=/var/lib/kubernetes/service-account-key.pem \\
--service-account-issuer=https://${KUBERNETES_PUBLIC_ADDRESS}:443 \\
--service-cluster-ip-range=10.32.0.0/24 \\
--service-node-port-range=30000-32767 \\
--tls-cert-file=/var/lib/kubernetes/kubernetes.pem \\
--tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
以下を参考にしています。
kube-apiserverkube-apiserver Synopsis The Kubernetes API server validates and configures d kubernetes.io
Kubernetesのコントローラーマネージャーの設定
kube-controller-managerのkubeconfigを移動させます。
sudo mv kube-controller-manager.kubeconfig /var/lib/kubernetes/
kube-controller-manager.serviceのsystemdユニットファイルを生成します。
cat <<EOF | sudo tee /etc/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes
[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
--bind-address=0.0.0.0 \\
--cluster-cidr=10.200.0.0/16 \\
--cluster-name=kubernetes \\
--cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \\
--cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \\
--kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\
--leader-elect=true \\
--root-ca-file=/var/lib/kubernetes/ca.pem \\
--service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \\
--service-cluster-ip-range=10.32.0.0/24 \\
--use-service-account-credentials=true \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
Kubernetesのschedulerの設定
sudo mkdir -p /etc/kubernetes/config/
kube-schedulerのkubeconfigを移動させます。
sudo mv kube-scheduler.kubeconfig /var/lib/kubernetes/
kube-scheduler.yamlを作成します。
cat <<EOF | sudo tee /etc/kubernetes/config/kube-scheduler.yaml
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
leaderElect: true
EOF
Version1.24から、apiVersion v1beta1が利用できなくなっています。
kube-scheduler.serviceのsystemdユニットファイルを生成します。
cat <<EOF | sudo tee /etc/systemd/system/kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes
[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
--config=/etc/kubernetes/config/kube-scheduler.yaml \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
コントローラーサービスの起動
sudo systemctl daemon-reload
sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler
sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler
Kubernetes APIサーバーは初期化が完了するまで30秒くらいかかります。
確認
コントローラの各コンポーネントの状態を確認します。
kubectl cluster-info --kubeconfig admin.kubeconfig
出力例
Kubernetes control plane is running at https://127.0.0.1:6443
ホストファイルのエントリー追加
kubectl execコマンドを実行する際、コントローラノードはそれぞれのワーカーノードの名前解決を行う必要があります。
ホストインスタンスのhostsファイルに、ワーカーノードのホストエントリーを手動で追加します。
cat <<EOF | sudo tee -a /etc/hosts
10.0.1.20 ip-10-0-1-20
10.0.1.21 ip-10-0-1-21
10.0.1.22 ip-10-0-1-22
EOF
この手順を実行しないと、後続のテストが失敗します。
kubelet認証のRBAC設定
このステップでは、Kubernetes APIサーバーが各ワーカーノードのKubelet APIにアクセスできるようにRBACによるアクセス許可を設定します。
メトリックやログの取得、Pod内でのコマンドの実行には、Kubernetes APIサーバーからKubelet APIへのアクセスが必要です。
このチュートリアルでは、Kubelet authorization-modeフラグをWebhookに設定します。Webhookモードは SubjectAccessReview APIを使用して認証を行います。
ここで実行する以下のコマンドはクラスター全体に作用します。
任意のコントローラーノードにログインして一度だけ実行してください。
以下では、自身の端末からcontroller-0ノードにログインする所から手順を記載しています。
external_ip=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=controller-0" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
ssh -i kubernetes.id_rsa ubuntu@${external_ip}
kube-apiserver-to-kubeletという名前でClusterRoleを作ります。
このロールに、Kubelet APIにアクセスしてポッドの管理に関連するタスクを実行する権限を付与します。
cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
verbs:
- "*"
EOF
Kubernetes APIサーバーは、–kubelet-client-certificateフラグで定義したクライアント証明書を使って、kubernetesユーザーとしてKubeletに対して認証を行います。
system:kube-apiserver-to-kubeletのClusterRoleをkubernetesユーザーにバインドします。
cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubernetes
EOF
Kubernetesクラスターのパブリックエンドポイントを有効化する
以下のコマンドは、EC2インスタンスではなく自身のMacもしくはLinux環境のラップトップで行います。
kubernetes-the-hard-wayロードバランサーのアドレスを取得します。
KUBERNETES_PUBLIC_ADDRESS=$(aws elbv2 describe-load-balancers \
--load-balancer-arns ${LOAD_BALANCER_ARN} \
--output text --query 'LoadBalancers[].DNSName')
echo ${KUBERNETES_PUBLIC_ADDRESS}
HTTPリクエストを作成しKubernetesのVersion情報を取得します。
curl -k --cacert ca.pem https://${KUBERNETES_PUBLIC_ADDRESS}/version
出力例
{
"major": "1",
"minor": "24",
"gitVersion": "v1.24.0",
"gitCommit": "4ce5a8954017644c5420bae81d72b09b735c21f0",
"gitTreeState": "clean",
"buildDate": "2022-05-03T13:38:19Z",
"goVersion": "go1.18.1",
"compiler": "gc",
"platform": "linux/amd64"
}%
09-ワーカーノードの起動
このセクションでは、3つのKubernetesワーカーノードをプロビジョニングします。以下のコンポーネントを各ノードにインストールします。
- runc
- gVisor
- container networking plugins
- containerd
- kubelet
- kube-proxy
準備
この手順で記載されているコマンドは、worker-0,worker-1、worker-2の各ワーカーノードで実行する必要があります。
まずはsshコマンドで各ワーカーノードにログインします
for instance in worker-0 worker-1 worker-2; do
external_ip=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=${instance}" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
echo ssh -i kubernetes.id_rsa ubuntu@$external_ip
done
ここからの手順は、直前のコマンドによって出力されたそれぞれのIPアドレスにssh接続して行います。
(3台のインスタンス全てで同じコマンドを実行する必要があります)
tmuxを使えば、容易に複数のインスタンスで同時にコマンドを実行できます。詳細はこちらをご覧ください。
Kubernetesのワーカーノードのプロビジョング
使用するライブラリをインストールします。
sudo apt-get update
sudo apt-get -y install socat conntrack ipset
socatはkubectl port-forwardコマンドに必要なバイナリです。
swapの無効化
swapが有効になっている場合、kubeletの起動に失敗します。
以下のコマンドでswapが有効になっているかどうかを確認します。
sudo swapon --show
出力が何もない場合はswapは無効化されています。
有効になっている場合は以下のコマンドでswapを無効化します。
sudo swapoff -a
ワーカーノードに必要なコンポーネントのバイナリをダウンロードしてインストールします。
wget -q --show-progress --https-only --timestamping \
https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.24.0/crictl-v1.24.0-linux-amd64.tar.gz \
https://github.com/opencontainers/runc/releases/download/v1.1.3/runc.amd64 \
https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz \
https://github.com/containerd/containerd/releases/download/v1.6.6/containerd-1.6.6-linux-amd64.tar.gz \
https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/linux/amd64/kubectl \
https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/linux/amd64/kube-proxy \
https://storage.googleapis.com/kubernetes-release/release/v1.24.0/bin/linux/amd64/kubelet
インストールする先のディレクトリを作成します。
sudo mkdir -p \
/etc/cni/net.d \
/opt/cni/bin \
/var/lib/kubelet \
/var/lib/kube-proxy \
/var/lib/kubernetes \
/var/run/kubernetes
ワーカーのバイナリを展開します。
mkdir containerd
tar -xvf crictl-v1.24.0-linux-amd64.tar.gz
tar -xvf containerd-1.6.6-linux-amd64.tar.gz -C containerd
sudo tar -xvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin/
sudo mv runc.amd64 runc
chmod +x crictl kubectl kube-proxy kubelet runc
sudo mv crictl kubectl kube-proxy kubelet runc /usr/local/bin/
sudo mv containerd/bin/* /bin/
CNIネットワーキングの設定
EC2インスタンスのPod用に設定されているCIDR範囲を取得します。
POD_CIDR=$(curl -s http://169.254.169.254/latest/user-data/ \
| tr "|" "\n" | grep "^pod-cidr" | cut -d"=" -f2)
echo "${POD_CIDR}"
bridgeネットワークの設定ファイルを作ります。
cat <<EOF | sudo tee /etc/cni/net.d/10-bridge.conf
{
"cniVersion": "1.0.0",
"name": "bridge",
"type": "bridge",
"bridge": "cnio0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"ranges": [
[{"subnet": "${POD_CIDR}"}]
],
"routes": [{"dst": "0.0.0.0/0"}]
}
}
EOF
loopbackネットワークの設定ファイルを作ります。
cat <<EOF | sudo tee /etc/cni/net.d/99-loopback.conf
{
"cniVersion": "1.0.0",
"name": "lo",
"type": "loopback"
}
EOF
containerdの設定
containerdの設定ファイルを作成します。
sudo mkdir -p /etc/containerd/
cat << EOF | sudo tee /etc/containerd/config.toml
[plugins]
[plugins.cri.containerd]
snapshotter = "overlayfs"
[plugins.cri.containerd.default_runtime]
runtime_type = "io.containerd.runtime.v1.linux"
runtime_engine = "/usr/local/bin/runc"
runtime_root = ""
EOF
containerd.serviceのsystemdユニットファイルを作成します。
cat <<EOF | sudo tee /etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target
[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
[Install]
WantedBy=multi-user.target
EOF
Kubeletの設定
WORKER_NAME=$(curl -s http://169.254.169.254/latest/user-data/ \
| tr "|" "\n" | grep "^name" | cut -d"=" -f2)
echo "${WORKER_NAME}"
sudo mv ${WORKER_NAME}-key.pem ${WORKER_NAME}.pem /var/lib/kubelet/
sudo mv ${WORKER_NAME}.kubeconfig /var/lib/kubelet/kubeconfig
sudo mv ca.pem /var/lib/kubernetes/
kubelet-config.yaml設定ファイルを作ります。
cat <<EOF | sudo tee /var/lib/kubelet/kubelet-config.yaml
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
enabled: true
x509:
clientCAFile: "/var/lib/kubernetes/ca.pem"
authorization:
mode: Webhook
clusterDomain: "cluster.local"
clusterDNS:
- "10.32.0.10"
podCIDR: "${POD_CIDR}"
resolvConf: "/run/systemd/resolve/resolv.conf"
runtimeRequestTimeout: "15m"
tlsCertFile: "/var/lib/kubelet/${WORKER_NAME}.pem"
tlsPrivateKeyFile: "/var/lib/kubelet/${WORKER_NAME}-key.pem"
EOF
resolvconfはsystemd-resolvを使用してCoreDNSを実行するときにループを回避するために使用されます。
kubelet.servicesystemdユニットファイルを作成します。
cat <<EOF | sudo tee /etc/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service
[Service]
ExecStart=/usr/local/bin/kubelet \\
--config=/var/lib/kubelet/kubelet-config.yaml \\
--container-runtime=remote \\
--container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \\
--kubeconfig=/var/lib/kubelet/kubeconfig \\
--register-node=true \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
尚、Version1.24から以下のオプションが削除されています。
–image-pull-progress-deadline=2m
–network-plugin=cni
Kubernetes Proxyの設定
sudo mv kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig
kube-proxy-config.yaml設定ファイルを作成します。
cat <<EOF | sudo tee /var/lib/kube-proxy/kube-proxy-config.yaml
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
kubeconfig: "/var/lib/kube-proxy/kubeconfig"
mode: "iptables"
clusterCIDR: "10.200.0.0/16"
EOF
kube-proxy.servicesystemdユニットファイルを作成します。
cat <<EOF | sudo tee /etc/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes
[Service]
ExecStart=/usr/local/bin/kube-proxy \\
--config=/var/lib/kube-proxy/kube-proxy-config.yaml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
ワーカーのサービス群の起動
sudo systemctl daemon-reload
sudo systemctl enable containerd kubelet kube-proxy
sudo systemctl start containerd kubelet kube-proxy
ここまでの手順を各ワーカーノード、worker-0、worker-1、worker-2で実行します。
確認
以下のコマンドは、自身のMacもしくはLinux端末から実行します。
登録されているKubernetesノードの一覧を表示させます。
external_ip=$(aws ec2 describe-instances --filters \
"Name=tag:Name,Values=controller-0" \
"Name=instance-state-name,Values=running" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
ssh -i kubernetes.id_rsa ubuntu@${external_ip} kubectl get nodes --kubeconfig admin.kubeconfig
出力例
NAME STATUS ROLES AGE VERSION
ip-10-0-1-20 Ready <none> 32s v1.24.0
ip-10-0-1-21 Ready <none> 29s v1.24.0
ip-10-0-1-22 Ready <none> 26s v1.24.0
10-リモートアクセス用のkubectl設定
このセクションでは、adminユーザーのcredenialに基づいた、kubectlコマンドラインユーティリティ用のkubeconfigファイルを生成します。
adminのクライアント証明書の生成に使用したディレクトリと同じディレクトリでコマンドを実行してください。
Admin Kubernetes設定ファイルを生成
各kubeconfigは、Kubernetes APIサーバーと接続できる必要があります。
高可用性を実現するために、Kubernetes APIサーバーの前に設置した外部ロードバランサーに割り当てられたIPアドレスを使用します。
adminユーザーを認証するkubeconfigファイルを生成します。
KUBERNETES_PUBLIC_ADDRESS=$(aws elbv2 describe-load-balancers \
--load-balancer-arns ${LOAD_BALANCER_ARN} \
--output text --query 'LoadBalancers[].DNSName')
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.pem \
--embed-certs=true \
--server=https://${KUBERNETES_PUBLIC_ADDRESS}:443
kubectl config set-credentials admin \
--client-certificate=admin.pem \
--client-key=admin-key.pem
kubectl config set-context kubernetes-the-hard-way \
--cluster=kubernetes-the-hard-way \
--user=admin
kubectl config use-context kubernetes-the-hard-way
確認
remoteのKubernetesクラスタのノードの一覧を取得します。
kubectl get nodes
出力例
NAME STATUS ROLES AGE VERSION
ip-10-0-1-20 Ready <none> 89m v1.24.0
ip-10-0-1-21 Ready <none> 89m v1.24.0
ip-10-0-1-22 Ready <none> 89m v1.24.0
11-クラスタ内ネットワークの設定
ノードにスケジュールされたPodは、ノードのPod CIDR範囲からIPアドレスを受け取ります。この時点では、ネットワークルートが見つからないため、Podは異なるノードで実行されている他のPodと通信できません。
このセクションでは、ノードのPod CIDR範囲をノードの内部IPアドレスにマップするための、各ワーカーノードのルートを作成します。
本チュートリアルで紹介するモデルは一例であり、Kubernetesのネットワークモデルの実装は他にもあります。
ルーティングテーブルとルートを定義
このセクションでは、kubernetes-the-hard-wayVPCネットワーク内でルートを作るために必要な情報を集めます。
通常、この機能はflannel, calico, amazon-vpc-cin-k8s等のCNIプラグインによって提供されます。
これを手作業で行うことにより、これらのプラグインがバックグラウンドで何をしているのかを理解しやすくなります。
まずは各ワーカーインスタンスの内部IPアドレスとPod CIDR範囲を表示させます。
for instance in worker-0 worker-1 worker-2; do
instance_id_ip="$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=${instance}" \
--output text --query 'Reservations[].Instances[].[InstanceId,PrivateIpAddress]')"
instance_id="$(echo "${instance_id_ip}" | cut -f1)"
instance_ip="$(echo "${instance_id_ip}" | cut -f2)"
pod_cidr="$(aws ec2 describe-instance-attribute \
--instance-id "${instance_id}" \
--attribute userData \
--output text --query 'UserData.Value' \
| base64 --decode | tr "|" "\n" | grep "^pod-cidr" | cut -d'=' -f2)"
echo "${instance_ip} ${pod_cidr}"
aws ec2 create-route \
--route-table-id "${ROUTE_TABLE_ID}" \
--destination-cidr-block "${pod_cidr}" \
--instance-id "${instance_id}"
done
出力例
10.0.1.20 10.200.0.0/24
{
"Return": true
}
10.0.1.21 10.200.1.0/24
{
"Return": true
}
10.0.1.22 10.200.2.0/24
{
"Return": true
}
ルートの確認
各ワーカーインスタンスに対してネットワークルートを確認します。
aws ec2 describe-route-tables \
--route-table-ids "${ROUTE_TABLE_ID}" \
--query 'RouteTables[].Routes'
出力例
[
[
{
"DestinationCidrBlock": "10.200.0.0/24",
"InstanceId": "i-0cb0e48788838daa4",
"InstanceOwnerId": "523358537305",
"NetworkInterfaceId": "eni-0d5ff998bd2fb09c5",
"Origin": "CreateRoute",
"State": "active"
},
{
"DestinationCidrBlock": "10.200.1.0/24",
"InstanceId": "i-001c9deec822b1325",
"InstanceOwnerId": "523358537305",
"NetworkInterfaceId": "eni-04334cbdcbcf2cfd5",
"Origin": "CreateRoute",
"State": "active"
},
{
"DestinationCidrBlock": "10.200.2.0/24",
"InstanceId": "i-0055e9af229f7ea5d",
"InstanceOwnerId": "523358537305",
"NetworkInterfaceId": "eni-0c28e31352ccd881a",
"Origin": "CreateRoute",
"State": "active"
},
{
"DestinationCidrBlock": "10.0.0.0/16",
"GatewayId": "local",
"Origin": "CreateRouteTable",
"State": "active"
},
{
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": "igw-0f1932111bd00691f",
"Origin": "CreateRoute",
"State": "active"
}
]
]
12-DNSクラスタアドオンの導入
このセクションでは、Kubernetesクラスタ内で動いているアプリケーションに、CoreDNSを使ったDNSベースのサービスディスカバリを提供するDNSアドオンをデプロイします。
DNSクラスターアドオン
corednsクラスターアドオンをデプロイします。
cat > coredns-1.9.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: coredns
namespace: kube-system
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
rules:
- apiGroups:
- ""
resources:
- endpoints
- services
- pods
- namespaces
verbs:
- list
- watch
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:coredns
subjects:
- kind: ServiceAccount
name: coredns
namespace: kube-system
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
cache 30
loop
reload
loadbalance
}
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/name: "CoreDNS"
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
spec:
priorityClassName: system-cluster-critical
serviceAccountName: coredns
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
nodeSelector:
kubernetes.io/os: linux
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values: ["kube-dns"]
topologyKey: kubernetes.io/hostname
containers:
- name: coredns
image: coredns/coredns:1.9.3
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
args: [ "-conf", "/etc/coredns/Corefile" ]
volumeMounts:
- name: config-volume
mountPath: /etc/coredns
readOnly: true
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- all
readOnlyRootFilesystem: true
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /ready
port: 8181
scheme: HTTP
dnsPolicy: Default
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
annotations:
prometheus.io/port: "9153"
prometheus.io/scrape: "true"
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "CoreDNS"
spec:
selector:
k8s-app: kube-dns
clusterIP: 10.32.0.10
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
- name: metrics
port: 9153
protocol: TCP
EOF
kubectl apply -f coredns-1.9.yaml
出力例
serviceaccount/coredns created
clusterrole.rbac.authorization.k8s.io/system:coredns created
clusterrolebinding.rbac.authorization.k8s.io/system:coredns created
configmap/coredns created
deployment.apps/coredns created
service/kube-dns created
kube-dns deploymentによって作られたPodの確認を行います。
kubectl get pods -l k8s-app=kube-dns -n kube-system
出力例
NAME READY STATUS RESTARTS AGE
coredns-8494f9c688-jth4j 1/1 Running 0 46s
coredns-8494f9c688-p679g 1/1 Running 0 46s
確認
busybox deploymentを作成します。
kubectl run busybox --image=busybox:1.28 --command -- sleep 3600
busybox deploymentによって作られてPodを確認します。
kubectl get pods -l run=busybox
出力例
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 0 25s
busybox pod内からkubernetesserviceのDNS lookupを行います。
POD_NAME=$(kubectl get pods -l run=busybox -o jsonpath="{.items[0].metadata.name}")
echo ${POD_NAME}
kubectl exec -ti $POD_NAME -- nslookup kubernetes
出力例
ubernetes
Server: 10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local
13-スモークテスト
このセクションでは、Kubernetesクラスタが正しく機能していることを確認するためのタスクを実行します。
データの暗号化
このステップでは保存されているデータの暗号化を確認します。
generic secretを作ります。
kubectl create secret generic kubernetes-the-hard-way \
--from-literal="mykey=mydata"
etcdに保存されているkubernetes-the-hard-wayのsecretをhexdumpします。
external_ip=$(aws ec2 describe-instances --filters \
"Name=tag:Name,Values=controller-0" \
"Name=instance-state-name,Values=running" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
ssh -i kubernetes.id_rsa ubuntu@${external_ip} \
"sudo ETCDCTL_API=3 etcdctl get \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/ca.pem \
--cert=/etc/etcd/kubernetes.pem \
--key=/etc/etcd/kubernetes-key.pem\
/registry/secrets/default/kubernetes-the-hard-way | hexdump -C"
出力例
00000000 2f 72 65 67 69 73 74 72 79 2f 73 65 63 72 65 74 |/registry/secret|
00000010 73 2f 64 65 66 61 75 6c 74 2f 6b 75 62 65 72 6e |s/default/kubern|
00000020 65 74 65 73 2d 74 68 65 2d 68 61 72 64 2d 77 61 |etes-the-hard-wa|
00000030 79 0a 6b 38 73 3a 65 6e 63 3a 61 65 73 63 62 63 |y.k8s:enc:aescbc|
00000040 3a 76 31 3a 6b 65 79 31 3a 67 3f 76 23 d3 0f 9b |:v1:key1:g?v#...|
00000050 c2 92 14 54 6e 7f 26 41 a6 27 e0 a7 d6 9e 3f 67 |...Tn.&A.'....?g|
00000060 07 88 36 c9 99 ac dd e5 5f 44 e5 f0 7e 45 9b 0a |..6....._D..~E..|
00000070 04 ed 0c b8 77 0b a7 29 7c df 34 ec 4c 22 d6 36 |....w..)|.4.L".6|
00000080 f7 58 38 b9 5f 49 1f 0f b8 ac a6 ea 4d 23 95 0f |.X8._I......M#..|
00000090 aa 35 c8 39 eb 33 e2 c8 4c 70 5e f8 2c 05 ef 88 |.5.9.3..Lp^.,...|
000000a0 cc 41 3f da d2 05 93 3a 3c 4d 1c 33 a2 fe 78 fb |.A?....:<M.3..x.|
000000b0 ec fa 02 af cd c0 6d 8e dd 6d b7 5a e2 b1 f7 44 |......m..m.Z...D|
000000c0 3c ec d9 04 7d 9b 82 5e d4 22 fe 6f 5e 2b 47 aa |<...}..^.".o^+G.|
000000d0 56 76 13 a0 9c a4 ca a6 c1 46 a1 5e 1b a6 ab 9b |Vv.......F.^....|
000000e0 d8 71 e7 84 3c ed 94 a0 f6 b8 6e 11 2e 44 8e ab |.q..<.....n..D..|
000000f0 0f f4 89 9a ac e6 cb f6 8f 48 da 8e 0e c2 ba cf |.........H......|
00000100 c5 be 3f a4 c2 a0 38 29 78 23 a7 56 db b3 e0 20 |..?...8)x#.V... |
00000110 a3 ae d2 9b d7 8a 4b 3b 83 df ee 12 c5 71 1f e5 |......K;.....q..|
00000120 c6 5b 97 0a 98 02 9e 85 df db e2 70 44 37 35 b2 |.[.........pD75.|
00000130 a8 30 cf 79 b5 25 4b d3 7a 35 f6 cf 69 11 25 f2 |.0.y.%K.z5..i.%.|
00000140 bd 37 9e 2c 57 ed c0 d0 26 e0 8d b7 da bb 5e 76 |.7.,W...&.....^v|
00000150 0b e8 46 6d 6e 38 65 09 c2 0a |..Fmn8e...|
0000015a
etcdキーは、k8s:enc:aescbc:v1:key1というプレフィックスになっているはずです。これは、aescbcプロバイダがkey1という暗号化キーでデータを暗号化したことを表しています。
自端末からDeploymentの作成と管理
このステップではDeploymentの作成と管理ができているかを確認します。
nginx web serverのdeploymentを作成します。
kubectl create deployment nginx --image=nginx
nginx deploymentによってできたPodを確認します。
kubectl get pods -l app=nginx
出力例
NAME READY STATUS RESTARTS AGE
nginx-6799fc88d8-qfjkw 1/1 Running 0 13s
Port Forwarding
このステップでは、port forwardingを使って外部からアプリケーションにアクセスできるかを確認します。nginx podのフルネームを取得します。
POD_NAME=$(kubectl get pods -l app=nginx -o jsonpath="{.items[0].metadata.name}")
ローカルの8080ポートをnginx Podの80番ポートにフォワードします。
kubectl port-forward $POD_NAME 8080:80
出力例
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
別のターミナルからフォワードしたアドレスにHTTPリクエストを投げてみます。
curl --head http://127.0.0.1:8080
出力例
HTTP/1.1 200 OK
Server: nginx/1.21.6
Date: Mon, 25 Apr 2022 05:07:07 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
Connection: keep-alive
ETag: "61f01158-267"
Accept-Ranges: bytes
元のターミナルに戻ってnginx Podへのフォワーディングプロセスを止めます。
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080
^C
Logs
このステップでは、コンテナのログの取得ができるかを確認します。
nginx Podのログを表示します。
kubectl logs $POD_NAME
出力例
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/04/25 05:05:55 [notice] 1#1: using the "epoll" event method
2022/04/25 05:05:55 [notice] 1#1: nginx/1.21.6
2022/04/25 05:05:55 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2022/04/25 05:05:55 [notice] 1#1: OS: Linux 5.13.0-1022-aws
2022/04/25 05:05:55 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2022/04/25 05:05:55 [notice] 1#1: start worker processes
2022/04/25 05:05:55 [notice] 1#1: start worker process 32
2022/04/25 05:05:55 [notice] 1#1: start worker process 33
127.0.0.1 - - [25/Apr/2022:05:07:07 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.79.1" "-"
Exec
このステップではコンテナ内でのコマンド実行ができるかを確認します。nginxコンテナに入って、nginx -vを実行してnginxのバージョンを表示します。
kubectl exec -ti $POD_NAME -- nginx -v
出力例
nginx version: nginx/1.21.6
Services
このステップでは、Serviceを使ったアプリケーションの公開ができるかを確認します。nginx deploymentをNodePort を使って公開します。
kubectl expose deployment nginx --port 80 --type NodePort
クラスターがクラウドプロバイダーインテグレーションの設定がされていないため、LoadBalancerは使用できません。この手順では、クラウドプロバイダーインテグレーションの設定は対象外です。
nginx serviceでアサインされたノードのポート取得します。
NODE_PORT=$(kubectl get svc nginx \
--output=jsonpath='{range .spec.ports[0]}{.nodePort}')
nginxノードポートへのリモートアクセスを許可するファイアウォールのルール追加します。
aws ec2 authorize-security-group-ingress \
--group-id ${SECURITY_GROUP_ID} \
--protocol tcp \
--port ${NODE_PORT} \
--cidr 0.0.0.0/0
nginxのpodが実行されているワーカーノード名を取得します。
INSTANCE_NAME=$(kubectl get pod $POD_NAME --output=jsonpath='{.spec.nodeName}')
ワーカーインスタンスのExternal IPアドレスを取得します。
EXTERNAL_IP=$(aws ec2 describe-instances --filters \
"Name=instance-state-name,Values=running" \
"Name=network-interface.private-dns-name,Values=${INSTANCE_NAME}.*.internal*" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
External IPとnginxのノードポートを使用してHTTPリクエストを送信します。
curl -I http://${EXTERNAL_IP}:${NODE_PORT}
出力例
HTTP/1.1 200 OK
Server: nginx/1.21.6
Date: Mon, 25 Apr 2022 05:12:16 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 25 Jan 2022 15:03:52 GMT
Connection: keep-alive
ETag: "61f01158-267"
Accept-Ranges: bytes
14-crictlを使用してワーカーノードのイメージ・ポッド・コンテナをチェックする
このセクションは、ワーカーノードにログインし、リソース一覧を確認します。このセクションで扱うコマンドは、立ち上がっている3台のワーカーノード全てで実行可能です。
external_ip=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=worker-0" \
--output text --query 'Reservations[].Instances[].PublicIpAddress')
ssh -i kubernetes.id_rsa ubuntu@${external_ip}
以下のコマンドを実行し、出力を確認します。
sudo crictl -r unix:///var/run/containerd/containerd.sock images
出力例
IMAGE TAG IMAGE ID SIZE
docker.io/coredns/coredns 1.8.3 3885a5b7f138c 12.9MB
docker.io/coredns/coredns 1.9.3 5185b96f0becf 14.8MB
docker.io/library/busybox 1.28 8c811b4aec35f 728kB
k8s.gcr.io/pause 3.6 6270bb605e12e 302kB
以下のコマンドを実行し、出力を確認します。
sudo crictl -r unix:///var/run/containerd/containerd.sock pods
出力例
POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME
948e94faa3aad 21 hours ago Ready busybox default 0 (default)
以下のコマンドを実行し、出力を確認します。
sudo crictl -r unix:///var/run/containerd/containerd.sock ps
出力例
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
65c829a4a642c 8c811b4aec35f 46 minutes ago Running busybox 20 948e94faa3aad busybox
15-後片付け
このセクションでは、これまでに作成してきたAWSに関するリソースを削除します。
EC2インスタンス
コントローラーノード、ワーカーノードを削除します。
aws ec2 terminate-instances \
--instance-ids \
$(aws ec2 describe-instances \
--filter "Name=tag:Name,Values=controller-0,controller-1,controller-2,worker-0,worker-1,worker-2" \
--output text --query 'Reservations[].Instances[].InstanceId')
aws ec2 delete-key-pair --key-name kubernetes
Networking
外部ロードバランサー、VPC等のネットワークリソースを削除します。
aws elbv2 delete-load-balancer --load-balancer-arn "${LOAD_BALANCER_ARN}"
aws elbv2 delete-target-group --target-group-arn "${TARGET_GROUP_ARN}"
aws ec2 delete-security-group --group-id "${SECURITY_GROUP_ID}"
ROUTE_TABLE_ASSOCIATION_ID="$(aws ec2 describe-route-tables \
--route-table-ids "${ROUTE_TABLE_ID}" \
--output text --query 'RouteTables[].Associations[].RouteTableAssociationId')"
aws ec2 disassociate-route-table --association-id "${ROUTE_TABLE_ASSOCIATION_ID}"
aws ec2 delete-route-table --route-table-id "${ROUTE_TABLE_ID}"
aws ec2 detach-internet-gateway \
--internet-gateway-id "${INTERNET_GATEWAY_ID}" \
--vpc-id "${VPC_ID}"
aws ec2 delete-internet-gateway --internet-gateway-id "${INTERNET_GATEWAY_ID}"
aws ec2 delete-subnet --subnet-id "${SUBNET_ID}"
aws ec2 delete-vpc --vpc-id "${VPC_ID}"
16-おわりに
今回はツールを使わずにKubernetesのクラスタをAWSで構築する方法を紹介しました。
Kubernetesの初学者や資格試験対策のお役に立てれば幸いです。