Help us understand the problem. What is going on with this article?

kubernetes the hard way を AWS でやってみた(全文和訳有り)

kubernetes the hard wayをご存じでしょうか?
kuberenetesクラスターを手作業で構築することによってkubernetesへの理解を深めようという意図で作成されたチュートリアルです。

自分は今まで何となくの知識でkubernetesを使っていたので、今回復習のためにkubernetes the hard wayをやってみました。

オリジナルのチュートリアルはGCP環境で構築を行っていますが、有志の方がAWS環境用のチュートリアルを作成されていたので今回はそちらをやってみました。
それとせっかくなのでAWS用チュートリアルの日本語版を作ってみました。

個人的にはやってみてとても勉強になったのでお勧めです。皆さんもよければぜひ。

なお自分は以下のエントリーを見つつチュートリアルをやりました。こちらもとても勉強になるのでぜひ。

Kubernetes The Hard Wayする
Kubernetes: 構成コンポーネント一覧
KubernetesのTLS証明書

※このチュートリアルはオリジナルその日本語訳(GCP環境)AWS用チュートリアルを基に作成したものであり、私がゼロから作成したものではありません。


00-kubernetes the hard way (はじめに)

Kubernetes Hard Wayでは、Kubernetesの設定を一から進めます。

なので、このラボは、完全に自動化されて管理されたKubernetesクラスタを作るコマンドを探している人のためのものではありません。

このKubernetes The Hard Wayは学習することに最適化されています。
Kubernetesクラスタを立ち上げるための必要な各タスクを確実に理解するための、長い道のりが示されています。

想定読者

本番用のKubernetesクラスタをサポートすることを計画していて、かつ、Kubenretesクラスタのすべての部品がどのように組み合わさっているかを理解したいという人向けです。

今回出来上がるクラスタの詳細

Kubernetes The Hard Wayでは、コンポーネント間のエンドツーエンドの暗号化とRBAC認証ができる、可用性の高いKubernetesクラスタを作ります。

使うコンポーネントとそのバージョン一覧は下記の通りです

Kubernetes 1.15.3
containerd Container Runtime 1.2.9
gVisor 08879266fef3a67fac1a77f1ea133c3ac75759dd
CNI Container Networking 0.8.2
etcd 3.3.10

このチュートリアルではAWSを使用します

では、はじめていきましょう!

01-Prerequisites

Amazon Web Services

このチュートリアルではAmazon Web Service(以下AWS)を利用して、kubernetesクラスターを立ち上げます。
このチュートリアルを通して掛かる費用は、24時間あたり2ドル未満です。

また、今回使用するリソースはAWSの無料枠を超えるので、チュートリアル終了後には作成したリソースをクリーンアップし、不要なコストが発生しないよう注意してください。

Amazon Web Services CLI

以降の手順は、デプロイ用インスタンス(適当なEC2インスタンスを立ち上げる)で実行してください。
このデプロイ用インスタンスはクラスター立ち上げのための各種設定を行うためのものであり、kubernetesクラスターのコンポーネントではありません。

AWS CLIのインストール

AWSの公式ドキュメントに従って、AWS CLIをインストールし、必要な設定を行います。

インストールが終了したら、以下のコマンドでAWS CLIが有効であることを確認します。

aws --version

デフォルトリージョンの設定

このチュートリアルで使用するデフォルトのリージョンを設定します

AWS_REGION=us-west-1
aws configure set default.region $AWS_REGION

tmuxを使ってパラレルにコマンドを打てるようにする

一応おすすめ設定として書かれているので興味がある人は下記を見てみてください。

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/01-prerequisites.md#running-commands-in-parallel-with-tmux

02-クライアントツールのインストール

この手順ではcfssl, cfssljson, kubectlのインストールを行います。

CFSSLとCFSSLJSONのインストール

cfsslcfssljsonPKIの環境構築とTLSの証明書発行に使います。

OS Xでのインストール

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
sudo mv cfssl_linux-amd64 /usr/local/bin/cfssl
sudo mv cfssljson_linux-amd64 /usr/local/bin/cfssljson

確認

cfssl のバージョンが 1.2.0 以上であることを確認します

% cfssl version
Version: 1.2.0
Revision: dev
Runtime: go1.6

(cfssljsonにはバージョンを表示するコマンドがありません)

kubectlのインストール

kubectlはKubernetes API Serverとの通信に使用されるコマンドラインツールです。
今回はバージョン1.15.3以上が必要になります。

OS Xでのインストール

curl -o kubectl https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/darwin/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

Linuxでのインストール

wget https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

確認

インストールされたkubectlのバージョンが1.15.3以上であることを確認します。

% kubectl version --client
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.3", GitCommit:"2d3c76f9091b6bec110a5e63777c332469e0cba2", GitTreeState:"clean", BuildDate:"2019-08-19T12:38:00Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"darwin/amd64"}

03-Provisioning Compute Resources

リソースについての説明は元ネタか、こちらの日本語訳の方を確認してください。
以下、デプロイ用インスタンスで実行するコマンドを記載します。

Networking

VPC

VPC_ID=$(aws ec2 create-vpc --cidr-block 10.240.0.0/24 --output text --query 'Vpc.VpcId')
aws ec2 create-tags --resources ${VPC_ID} --tags Key=Name,Value=kubernetes
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

SUBNET_ID=$(aws ec2 create-subnet \
  --vpc-id ${VPC_ID} \
  --cidr-block 10.240.0.0/24 \
  --output text --query 'Subnet.SubnetId')
aws ec2 create-tags --resources ${SUBNET_ID} --tags Key=Name,Value=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

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

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.240.0.0/24
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 - ロードバランサーの作成

  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.240.0.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_PUBLIC_ADDRESS=$(aws elbv2 describe-load-balancers \
  --load-balancer-arns ${LOAD_BALANCER_ARN} \
  --output text --query 'LoadBalancers[].DNSName')

各種インスタンス

Instance Image

IMAGE_ID=$(aws ec2 describe-images --owners 099720109477 \
  --filters \
  'Name=root-device-type,Values=ebs' \
  'Name=architecture,Values=x86_64' \
  'Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*' \
  | jq -r '.Images|sort_by(.Name)[-1]|.ImageId')

SSH Key Pair

aws ec2 create-key-pair --key-name kubernetes --output text --query 'KeyMaterial' > kubernetes.id_rsa
chmod 600 kubernetes.id_rsa

Kubernetes コントローラーノード

今回は t3.micro インスタンスを使用します

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.240.0.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 ワーカーノード

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.240.0.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-Provisioning a CA and Generating TLS Certificates

この手順では、CloudFlareのPKIツールキットである cfsslを使用してPKI基盤をプロビジョニングします。
そして、PKI基盤を利用して認証局を作り、admin用のTLS証明書、etcd、kube-apiserver、kube-controller-manager、kube-scheduler、 kubelet、kube-proxyの各コンポーネント用TLS証明書を生成します。

認証局(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コンポーネントで使うクライアント証明書とサーバー証明書、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の認可のためには、Kubeletは、system:nodes groupの中の system:node:<nodeName> というユーザー名で認証されるように証明書を作成しなければなりません。

このステップでは、KubernetesワーカーノードごとにNode Authorizerの要求を満たす証明書と秘密鍵を発行します。

for i in 0 1 2; do
  instance="worker-${i}"
  instance_hostname="ip-10-240-0-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}" \
    --output text --query 'Reservations[].Instances[].PublicIpAddress')

  internal_ip=$(aws ec2 describe-instances \
    --filters "Name=tag:Name,Values=${instance}" \
    --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 サーバーの証明書と秘密鍵を生成します。

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.240.0.10,10.240.0.11,10.240.0.12,${KUBERNETES_PUBLIC_ADDRESS},127.0.0.1,kubernetes.default \
  -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}" \
    --output text --query 'Reservations[].Instances[].PublicIpAddress')

  scp -i kubernetes.id_rsa ca.pem ${instance}-key.pem ${instance}.pem ubuntu@${external_ip}:~/
done

コントローラーインスタンスにも同様に配置します。
(配置するもの:CAの証明書、APIサーバの証明書と秘密鍵、サービスアカウント振り出し用キーペア)

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 \
    ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
    service-account-key.pem service-account.pem ubuntu@${external_ip}:~/
done

kube-proxy、kube-controller-manager、kube-scheduler、kubelet のクライアント証明書は次の手順のクライアント認証設定ファイルの生成で使います。

05-Generating Kubernetes Configuration Files for Authentication

この手順では、Kubernetes APIサーバーがKubernetesのクライアントを配置、認証できるようにするためのkubeconfigs(Kubernetes構成ファイル)を生成します。

クライアントの認証設定

まずは、conttoller-managerkubeletkube-proxyscheduler、そして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')

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の配布

kubeletkube-proxyのkubecnofigをコピーし、各ワーカーノードに配置します

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')

  scp -i kubernetes.id_rsa \
    ${instance}.kubeconfig kube-proxy.kubeconfig ubuntu@${external_ip}:~/
done

kube-controller-managerkube-schedulerkubeconfigをコピーし、各コントローラーノードに配置します。

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

06-Generating the Data Encryption Config and Key

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}" \
    --output text --query 'Reservations[].Instances[].PublicIpAddress')

  scp -i kubernetes.id_rsa encryption-config.yaml ubuntu@${external_ip}:~/
done

07-Bootstrapping the etcd Cluster

Kubernetesの各コンポーネントはステートレスになっており、クラスタの状態はetcdに格納され管理されています。(つまり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を使って並列にコマンドを走らせる

tmux を使えば、容易に複数のインスタンスで同時にコマンドを実行できます。こちら をご覧ください.

etcdのクラスタメンバーの起動

※繰り返しになりますが、ここからの手順は各コントローラーインスタンスで行ってください※

etcdのダウンロードとインストール

etcdのバイナリをgithubからDLします。

wget -q --show-progress --https-only --timestamping \
  "https://github.com/etcd-io/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz"

DLしたファイルを展開してetcdサーバーとetcdctlコマンドラインユーティリティを取り出します。

tar -xvf etcd-v3.3.10-linux-amd64.tar.gz
sudo mv etcd-v3.3.10-linux-amd64/etcd* /usr/local/bin/

etcdサーバーの設定

sudo mkdir -p /etc/etcd /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)

各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]
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.240.0.10:2380,controller-1=https://10.240.0.11:2380,controller-2=https://10.240.0.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-0controller-1controller-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
f98dc20bce6225a0, started, controller-0, https://10.240.0.10:2380, https://10.240.0.10:2379
ffed16798470cab5, started, controller-1, https://10.240.0.11:2380, https://10.240.0.11:2379

08-Bootstrapping the Kubernetes Control Plane

この手順では、3つのインスタンスを使って可用性の高いKubernetesコントロールプレーンを作ります。

合わせて、Kubernetes API Serverを外部クライアントに公開する外部ロードバランサーも作成します。

各ノードに、Kubernetes API ServerScheduler、およびController Managerのコンポーネントをインストールします。

Prerequisites

前のステップと同じくこのステップでも、controller-0controller-1controller-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を使って並列にコマンドを走らせる

tmux を使えば、容易に複数のインスタンスで同時にコマンドを実行できます。こちら をご覧ください.

Kubernetesコントロールプレーンのプロビジョニング

Kubernetesの設定をおくディレクトリを作成します。

sudo mkdir -p /etc/kubernetes/config

KubernetesコントローラーのバイナリのDLとインストール

Kubernetesの公式のリリースバイナリをDLします

wget -q --show-progress --https-only --timestamping \
  "https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kube-apiserver" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kube-controller-manager" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kube-scheduler" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kubectl"

DLしたバイナリをインストールします。

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)

kube-apiserver.serviceのsystemdのユニットファイルを生成します。

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 \\
  --enable-swagger-ui=true \\
  --encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
  --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.240.0.10:2379,https://10.240.0.11:2379,https://10.240.0.12:2379 \\
  --event-ttl=1h \\
  --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 \\
  --kubelet-https=true \\
  --runtime-config=api/all \\
  --service-account-key-file=/var/lib/kubernetes/service-account.pem \\
  --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

参考:https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/

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 \\
  --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/v1alpha1
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
  leaderElect: true
EOF

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 get componentstatuses

出力

NAME                 STATUS    MESSAGE             ERROR
controller-manager   Healthy   ok
scheduler            Healthy   ok
etcd-0               Healthy   {"health":"true"}
etcd-2               Healthy   {"health":"true"}
etcd-1               Healthy   {"health":"true"}

やったー! コントロールプレーンが起動しています!

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/v1beta1
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-kubeletClusterRolekubernetesユーザーにバインドします。

cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
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クラスターのパブリックエンドポイントを有効化する

以下のコマンドはデプロイ用インスタンス(各AWSリソースを作成するのに使用したインスタンス)で行ってください。

kubernetes-the-hard-wayロードバランサーのアドレスを取得する

KUBERNETES_PUBLIC_ADDRESS=$(aws elbv2 describe-load-balancers \
  --load-balancer-arns ${LOAD_BALANCER_ARN} \
  --output text --query 'LoadBalancers[].DNSName')

HTTPリクエストを作成しKubernetesのVersion情報を取得する

curl -k --cacert ca.pem https://${KUBERNETES_PUBLIC_ADDRESS}/version

出力例

{
  "major": "1",
  "minor": "13",
  "gitVersion": "v1.13.4",
  "gitCommit": "c27b913fddd1a6c480c229191a087698aa92f0b1",
  "gitTreeState": "clean",
  "buildDate": "2019-02-28T13:30:26Z",
  "goVersion": "go1.11.5",
  "compiler": "gc",
  "platform": "linux/amd64"
}

09-Bootstrapping the Kubernetes Worker Nodes

このステップでは、3つのKubernetesワーカーノードをブートストラップします。

下記のコンポーネントを各ノードにインストールします。

runc, gVisor, container networking plugins, containerd, kubelet, kube-proxy.

準備

この手順で記載されているコマンドは、worker-0worker-1worker-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を使って並列にコマンドを走らせる

tmux を使えば、容易に複数のインスタンスで同時にコマンドを実行できます。こちら をご覧ください.

Kubernetesのワーカーノードのプロビジョング

使うライブラリをインストールします。

sudo apt-get update
sudo apt-get -y install socat conntrack ipset

socatはkubectl port-forwardコマンドに必要となります。

ワーカーのバイナリをDLしてインストール

wget -q --show-progress --https-only --timestamping \
  https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.15.0/crictl-v1.15.0-linux-amd64.tar.gz \
  https://storage.googleapis.com/kubernetes-the-hard-way/runsc \
  https://github.com/opencontainers/runc/releases/download/v1.0.0-rc8/runc.amd64 \
  https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz \
  https://github.com/containerd/containerd/releases/download/v1.2.9/containerd-1.2.9.linux-amd64.tar.gz \
  https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kubectl \
  https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kube-proxy \
  https://storage.googleapis.com/kubernetes-release/release/v1.15.3/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

ワーカーのバイナリをインストールします。

chmod +x kubectl kube-proxy kubelet runc.amd64 runsc
sudo mv runc.amd64 runc
sudo mv kubectl kube-proxy kubelet runc runsc /usr/local/bin/
sudo tar -xvf crictl-v1.15.0-linux-amd64.tar.gz -C /usr/local/bin/
sudo tar -xvf cni-plugins-linux-amd64-v0.8.2.tgz -C /opt/cni/bin/
sudo tar -xvf containerd-1.2.9.linux-amd64.tar.gz -C /

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": "0.3.1",
    "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": "0.3.1",
    "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 = ""
    [plugins.cri.containerd.untrusted_workload_runtime]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/bin/runsc"
      runtime_root = "/run/containerd/runsc"
EOF

信頼できないワークロードはgVisor(runsc)ランタイムが使われます

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}"
runtimeRequestTimeout: "15m"
tlsCertFile: "/var/lib/kubelet/${WORKER_NAME}.pem"
tlsPrivateKeyFile: "/var/lib/kubelet/${WORKER_NAME}-key.pem"
resolvConf: "/run/systemd/resolve/resolv.conf"
EOF

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 \\
  --image-pull-progress-deadline=2m \\
  --kubeconfig=/var/lib/kubelet/kubeconfig \\
  --network-plugin=cni \\
  --register-node=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Kubernetes Proxyの設定

sudo mv kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig

Create the kube-proxy-config.yaml configuration file:

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-config.yaml 設定ファイルを作ります。

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-0worker-1worker-2で実行してください!

確認

現在作業中のインスタンス(ワーカーノード)には、このステップを完了できる権限がありません。
このため、以下のコマンドは任意のコントローラーノードにログインして行ってください。
以下のコマンドは、デプロイ用インスタンス(各AWSリソースを作成する際に使用したインスタンス)からcontroller-0ノードにログインする所から記載してあります。

登録されているKubernetesノードの一覧を表示させます。

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}

kubectl get nodes --kubeconfig admin.kubeconfig

出力

NAME             STATUS   ROLES    AGE   VERSION
ip-10-240-0-20   Ready    <none>   51s   v1.13.4
ip-10-240-0-21   Ready    <none>   51s   v1.13.4
ip-10-240-0-22   Ready    <none>   51s   v1.13.4
socat, conntrack, ipsetのそれぞれの役割がよくわかっていない

AWS、GCPともに169.254.169.254というIPアドレスはインスタンスメタデータの取得に使われる

CNIネットワークの設定の所、何やってるかもう一度復習する必要あり

10-Configuring kubectl for Remote Access

このステップでは、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 componentstatuses

出力例

NAME                 STATUS    MESSAGE             ERROR
controller-manager   Healthy   ok
scheduler            Healthy   ok
etcd-1               Healthy   {"health":"true"}
etcd-2               Healthy   {"health":"true"}
etcd-0               Healthy   {"health":"true"}

remoteのKubernetesクラスタのノードの一覧を取得します。

kubectl get nodes

出力例

NAME             STATUS   ROLES    AGE     VERSION
ip-10-240-0-20   Ready    <none>   3m35s   v1.13.4
ip-10-240-0-21   Ready    <none>   3m35s   v1.13.4
ip-10-240-0-22   Ready    <none>   3m35s   v1.13.4

11-Configuring kubectl for Remote Access

ノードにスケジュールされたPodは、ノードのPod CIDR範囲からIPアドレスを受け取ります。

この時点では、ネットワークルートが見つからないため、Podは異なるノードで実行されている他のPodと通信できません。

この手順では、ノードのPod CIDR範囲をノードの内部IPアドレスにマップするための、各ワーカーノードのルートを作成します。

Kubernetesのネットワークモデルの実装は他にもあります。

ルーティングテーブルとルート群

このセクションでは、kubernetes-the-hard-wayVPCネットワーク内でルートを作るために必要な情報を集めます。

通常、この機能はflanne, 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.240.0.20 10.200.0.0/24
{
    "Return": true
}
10.240.0.21 10.200.1.0/24
{
    "Return": true
}
10.240.0.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-0879fa49c49be1a3e",
            "InstanceOwnerId": "107995894928",
            "NetworkInterfaceId": "eni-0612e82f1247c6282",
            "Origin": "CreateRoute",
            "State": "active"
        },
        {
            "DestinationCidrBlock": "10.200.1.0/24",
            "InstanceId": "i-0db245a70483daa43",
            "InstanceOwnerId": "107995894928",
            "NetworkInterfaceId": "eni-0db39a19f4f3970f8",
            "Origin": "CreateRoute",
            "State": "active"
        },
        {
            "DestinationCidrBlock": "10.200.2.0/24",
            "InstanceId": "i-0b93625175de8ee43",
            "InstanceOwnerId": "107995894928",
            "NetworkInterfaceId": "eni-0cc95f34f747734d3",
            "Origin": "CreateRoute",
            "State": "active"
        },
        {
            "DestinationCidrBlock": "10.240.0.0/24",
            "GatewayId": "local",
            "Origin": "CreateRouteTable",
            "State": "active"
        },
        {
            "DestinationCidrBlock": "0.0.0.0/0",
            "GatewayId": "igw-00d618a99e45fa508",
            "Origin": "CreateRoute",
            "State": "active"
        }
    ]
]

12-Deploying the DNS Cluster Add-on

この手順中、説明とコマンドが食い違っている箇所があったので修正してあります

このステップでは、Kubernetesクラスタ内で動いているアプリケーションに、CoreDNSを使ったDNSベースのサービスディスカバリを提供するDNSアドオンをデプロイします。

DNSクラスターアドオン

corednsクラスターアドオンをデプロイします。

kubectl create -f https://raw.githubusercontent.com/prabhatsharma/kubernetes-the-hard-way-aws/master/deployments/core-dns.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-7946767f6-trbvx   1/1     Running   0          42s

確認

busybox deploymentを作成します。

kubectl run busybox --image=busybox:1.28 --restart=Never -- sleep 3600

busybox deploymentによって作られてPodを確認します。

kubectl get pod busybox

出力

NAME       READY     STATUS    RESTARTS   AGE
busybox   1/1       Running   0          45s

busybox pod内からkubernetesserviceのDNS lookupを行います。

kubectl exec -it busybox -- nslookup kubernetes

出力

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-Smoke Test

このステップでは、Kubernetesクラスタが正しく機能していることを確認するためのタスクを実行します。

データの暗号化

このステップでは保存されているデータの暗号化を確認します。

generic secretを作ります。

kubectl create secret generic kubernetes-the-hard-way --from-literal="mykey=mydata"

etcdに保存されているkubernetes-the-hard-waysecretをhexdumpします。

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}

controller-0ノードで以下のコマンドを実行します

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 7b 8e 59 78 0f 59 09  |:v1:key1:{.Yx.Y.|
00000050  e2 6a ce cd f4 b6 4e ec  bc 91 aa 87 06 29 39 8d  |.j....N......)9.|
00000060  70 e8 5d c4 b1 66 69 49  60 8f c0 cc 55 d3 69 2b  |p.]..fiI`...U.i+|
00000070  49 bb 0e 7b 90 10 b0 85  5b b1 e2 c6 33 b6 b7 31  |I..{....[...3..1|
00000080  25 99 a1 60 8f 40 a9 e5  55 8c 0f 26 ae 76 dc 5b  |%..`.@..U..&.v.[|
00000090  78 35 f5 3e c1 1e bc 21  bb 30 e2 0c e3 80 1e 33  |x5.>...!.0.....3|
000000a0  90 79 46 6d 23 d8 f9 a2  d7 5d ed 4d 82 2e 9a 5e  |.yFm#....].M...^|
000000b0  5d b6 3c 34 37 51 4b 83  de 99 1a ea 0f 2f 7c 9b  |].<47QK....../|.|
000000c0  46 15 93 aa ba 72 ba b9  bd e1 a3 c0 45 90 b1 de  |F....r......E...|
000000d0  c4 2e c8 d0 94 ec 25 69  7b af 08 34 93 12 3d 1c  |......%i{..4..=.|
000000e0  fd 23 9b ba e8 d1 25 56  f4 0a                    |.#....%V..|
000000ea

etcdキーは、k8s:enc:aescbc:v1:key1というプレフィックスになっているはずです。

これは、aescbcプロバイダがkey1という暗号化キーでデータを暗号化したことを表しています。

Deployment - To be run on local laptop

このステップでは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-65899c769f-xkfcn   1/1       Running   0          15s

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.17.3
Date: Sat, 14 Sep 2019 13:54:34 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 13 Aug 2019 08:50:00 GMT
Connection: keep-alive
ETag: "5d5279b8-264"
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

出力

127.0.0.1 - - [14/May/2018:13:59:21 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.52.1" "-"

Exec

このステップではコンテナ内でのコマンド実行ができるかを確認します。

nginxコンテナに入って、nginx -vを実行してnginxのバージョンを表示します。

kubectl exec -ti $POD_NAME -- nginx -v

出力

nginx version: nginx/1.17.3

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

ワーカーインスタンスから外部IPアドレスを取得します。

INSTANCE_NAME=$(kubectl get pod $POD_NAME --output=jsonpath='{.spec.nodeName}')

もしもあなたが今回クラスターをUS-EAST-1に立ち上げている場合、以下のコマンドを実行してください。

EXTERNAL_IP=$(aws ec2 describe-instances \
    --filters "Name=network-interface.private-dns-name,Values=${INSTANCE_NAME}.ec2.internal" \
    --output text --query 'Reservations[].Instances[].PublicIpAddress')

US-EAST-1以外のリージョンにクラスターを立ち上げている場合は、以下のコマンドを実行してください。

EXTERNAL_IP=$(aws ec2 describe-instances \
    --filters "Name=network-interface.private-dns-name,Values=${INSTANCE_NAME}.${AWS_REGION}.compute.internal" \
    --output text --query 'Reservations[].Instances[].PublicIpAddress')

外部IPアドレスとnginxノードポート組わせてHTTPリクエストを投げてみます。

curl -I http://${EXTERNAL_IP}:${NODE_PORT}

出力

HTTP/1.1 200 OK
Server: nginx/1.17.3
Date: Sat, 14 Sep 2019 13:54:34 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 13 Aug 2019 08:50:00 GMT
Connection: keep-alive
ETag: "5d5279b8-264"
Accept-Ranges: bytes

Untrusted Workloads

gVisorを使って信頼されていないワークロードが動かせるかを確認します。

untrustedPodを作ります。

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: untrusted
  annotations:
    io.kubernetes.cri.untrusted-workload: "true"
spec:
  containers:
    - name: webserver
      image: gcr.io/hightowerlabs/helloworld:2.0.0
EOF

確認

このセクションでは、割り当てられたワーカーノードを調べて、untrustedPodがgVisor(runsc)の下で実行されていることを確認します。

untrustedPodが実行されていることを確認します。

kubectl get pods -o wide
NAME                     READY     STATUS    RESTARTS   AGE       IP           NODE             NOMINATED NODE
busybox                  1/1       Running   0          5m        10.200.0.2   ip-10-240-0-20   <none>
nginx-64f497f8fd-l6b78   1/1       Running   0          3m        10.200.1.2   ip-10-240-0-21   <none>
untrusted                1/1       Running   0          8s        10.200.2.3   ip-10-240-0-22   <none>

untrustedPodが実行されているノードの名前を取得します。

INSTANCE_NAME=$(kubectl get pod untrusted --output=jsonpath='{.spec.nodeName}')

もしもあなたが今回クラスターをUS-EAST-1に立ち上げている場合、以下のコマンドを実行してください。

INSTANCE_IP=$(aws ec2 describe-instances \
    --filters "Name=network-interface.private-dns-name,Values=${INSTANCE_NAME}.ec2.internal" \
    --output text --query 'Reservations[].Instances[].PublicIpAddress')

US-EAST-1以外のリージョンにクラスターを立ち上げている場合は、以下のコマンドを実行してください。

INSTANCE_IP=$(aws ec2 describe-instances \
    --filters "Name=network-interface.private-dns-name,Values=${INSTANCE_NAME}.${AWS_REGION}.compute.internal" \
    --output text --query 'Reservations[].Instances[].PublicIpAddress')

ワーカーノードにSSH接続します

ssh -i kubernetes.id_rsa ubuntu@${INSTANCE_IP}

gVisorのもとで動いているコンテナの一覧を取得します。

sudo runsc --root  /run/containerd/runsc/k8s.io list
I0514 14:03:56.108368   14988 x:0] ***************************
I0514 14:03:56.108548   14988 x:0] Args: [runsc --root /run/containerd/runsc/k8s.io list]
I0514 14:03:56.108730   14988 x:0] Git Revision: 08879266fef3a67fac1a77f1ea133c3ac75759dd
I0514 14:03:56.108787   14988 x:0] PID: 14988
I0514 14:03:56.108838   14988 x:0] UID: 0, GID: 0
I0514 14:03:56.108877   14988 x:0] Configuration:
I0514 14:03:56.108912   14988 x:0]              RootDir: /run/containerd/runsc/k8s.io
I0514 14:03:56.109000   14988 x:0]              Platform: ptrace
I0514 14:03:56.109080   14988 x:0]              FileAccess: proxy, overlay: false
I0514 14:03:56.109159   14988 x:0]              Network: sandbox, logging: false
I0514 14:03:56.109238   14988 x:0]              Strace: false, max size: 1024, syscalls: []
I0514 14:03:56.109315   14988 x:0] ***************************
ID                                                                 PID         STATUS      BUNDLE                                                           CREATED                          OWNER
3528c6b270c76858e15e10ede61bd1100b77519e7c9972d51b370d6a3c60adbb   14766       running     /run/containerd/io.containerd.runtime.v1.linux/k8s.io/3528c6b270c76858e15e10ede61bd1100b77519e7c9972d51b370d6a3c60adbb   2018-05-14T14:02:34.302378996Z
7ff747c919c2dcf31e64d7673340885138317c91c7c51ec6302527df680ba981   14716       running     /run/containerd/io.containerd.runtime.v1.linux/k8s.io/7ff747c919c2dcf31e64d7673340885138317c91c7c51ec6302527df680ba981   2018-05-14T14:02:32.159552044Z
I0514 14:03:56.111287   14988 x:0] Exiting with status: 0

untrustedPodのIDを取得します。

POD_ID=$(sudo crictl -r unix:///var/run/containerd/containerd.sock pods --name untrusted -q)

untrustedPodの中で動いてるwebserverコンテナのIDを取得します。

CONTAINER_ID=$(sudo crictl -r unix:///var/run/containerd/containerd.sock ps -p ${POD_ID} -q)

gVisorrunscコマンドを使って、webserverコンテナの中で走っているプロセスを表示します。

sudo runsc --root /run/containerd/runsc/k8s.io ps ${CONTAINER_ID}

出力

I0514 14:05:16.499237   15096 x:0] ***************************
I0514 14:05:16.499542   15096 x:0] Args: [runsc --root /run/containerd/runsc/k8s.io ps 3528c6b270c76858e15e10ede61bd1100b77519e7c9972d51b370d6a3c60adbb]
I0514 14:05:16.499597   15096 x:0] Git Revision: 08879266fef3a67fac1a77f1ea133c3ac75759dd
I0514 14:05:16.499644   15096 x:0] PID: 15096
I0514 14:05:16.499695   15096 x:0] UID: 0, GID: 0
I0514 14:05:16.499734   15096 x:0] Configuration:
I0514 14:05:16.499769   15096 x:0]              RootDir: /run/containerd/runsc/k8s.io
I0514 14:05:16.499880   15096 x:0]              Platform: ptrace
I0514 14:05:16.499962   15096 x:0]              FileAccess: proxy, overlay: false
I0514 14:05:16.500042   15096 x:0]              Network: sandbox, logging: false
I0514 14:05:16.500120   15096 x:0]              Strace: false, max size: 1024, syscalls: []
I0514 14:05:16.500197   15096 x:0] ***************************
UID       PID       PPID      C         STIME     TIME      CMD
0         1         0         0         14:02     40ms      app
I0514 14:05:16.501354   15096 x:0] Exiting with status: 0

14-Check images/pods/containers on worker nodes using 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
gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64   1.14.7              5feec37454f45       10.9MB
gcr.io/google_containers/k8s-dns-kube-dns-amd64        1.14.7              5d049a8c4eec9       13.1MB
gcr.io/google_containers/k8s-dns-sidecar-amd64         1.14.7              db76ee297b859       11.2MB
k8s.gcr.io/pause                                       3.1                 da86e6ba6ca19       317kB
sudo crictl -r unix:///var/run/containerd/containerd.sock pods

出力

POD ID              CREATED             STATE               NAME                        NAMESPACE           ATTEMPT
9a304a19557f7       2 hours ago         Ready               kube-dns-864b8bdc77-c5vc2   kube-system         0
sudo crictl -r unix:///var/run/containerd/containerd.sock ps

出力

CONTAINER ID        IMAGE                                                                     CREATED             STATE               NAME                ATTEMPT
611bfea53997d       sha256:db76ee297b8597fc007b23a90619314b8405bb1df6dcad189df0a123a09e7ecc   2 hours ago         Running             sidecar             0
824f26368efc0       sha256:5feec37454f45d060c5f528c7d0bd4958df39e7ffd2e65ae42aae68bf78f69a5   2 hours ago         Running             dnsmasq             0
f3d35b783af1e       sha256:5d049a8c4eec92b21ca4be399c260166d96569a1a52d497f4a0365bb55c1a18c   2 hours ago         Running             kubedns             0

15-Cleaning Up

この手順では、今まで作ってきたリソースを削除します。

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}"

おつかれさまでした!
以上でkubernetes the hard wayは終了です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした