我在AWS上尝试了“以最困难的方式部署Kubernetes”(附全文翻译)

你是否了解”kubernetes the hard way”?
这是一个通过手动构建kubernetes集群来增进对kubernetes的理解意图而创建的教程。

由于以前对Kubernetes只有一些模糊的了解,我决定尝试做一遍《Kubernetes the hard way》作为复习。

原教程是在GCP环境下进行构建的,但由于有志者为AWS环境创建了教程,所以这次我尝试了那个教程。
另外,我想顺便制作了AWS教程的日文版。

我个人觉得这个经历很有收获,对学习很有帮助,所以我推荐大家也试一试。如果大家有兴趣的话,请一定不要错过。

同时,我在做教程的过程中查看了以下条目。这些也非常有学习价值,务必要看一看。

Kubernetes的艰难之路
Kubernetes: 组成组件列表
Kubernetes的TLS证书

此教程是基于原版、日语翻译版(GCP环境)和AWS教程而创建的,不是我从零开始创建的。


00- 以“Kubernetes:不间断的艰难之路”为题 (はじめに)

在Kubernetes Hard Way中,我们将从零开始配置Kubernetes。

因此,这个实验室并不是为那些寻找创建完全自动化且受管理的Kubernetes集群命令的人而设立的。

这个Kubernetes The Hard Way是专为学习而优化的。
它展示了一个漫长的过程,以确保对构建Kubernetes集群所需的每个任务有透彻的理解。

希望读者

我們正在計劃支援正式使用的Kubernetes集群,並且這是針對那些希望了解Kubernetes集群的所有組件是如何組合在一起的人。

这次要出现的聚类的详细信息。

通过Kubernetes The Hard Way,我们可以构建一个高可用的Kubernetes集群,实现组件之间的端到端加密和RBAC认证。

下面是使用的组件及其版本列表。

Kubernetes 1.15.3
containerd容器运行时1.2.9
gVisor 08879266fef3a67fac1a77f1ea133c3ac75759dd
CNI容器网络0.8.2
etcd 3.3.10

在这个教程中,我们将使用AWS。

现在,让我们开始吧!

01-先决条件

亚马逊云服务

在这个教程中,我们将使用亚马逊网络服务(AWS)来启动一个Kubernetes集群。
通过这个教程,每24小时的费用不超过2美元。

此外,由于本次使用的资源超出了AWS的免费限额,请在教程结束后清理所创建的资源,以防产生不必要的费用。请务必注意。

亚马逊网络服务命令行界面

请在部署用实例(启动一个适当的EC2实例)上按照以下步骤执行。
这个部署用实例是为了进行集群启动的各种配置而准备的,不是kubernetes集群的组件。

安装 AWS CLI

根据AWS官方文档的指示,安装AWS CLI并进行必要的配置。

安装完成后,可以使用以下命令确认AWS CLI的有效性。

aws --version

设定默认地区

在此教程中,您可以设置默认的区域。

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

使用tmux可以并行运行命令的功能。

如果你对此感兴趣的话,我建议你去参考下面列出的内容。

02-安装客户端工具

在这个步骤中,我们将安装cfssl、cfssljson和kubectl。

CFSSL和CFSSLJSON的安装

cfssl和cfssljson用于搭建PKI环境和发行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时尝试预编译安装,可能会遇到问题。在这种情况下,请使用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服务器进行通信的命令行工具。
此次需要版本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-资源的分配与计算

请参考原始资料或者确认这里的日文翻译来了解有关资源的说明。
下面是在部署实例上执行的命令。

网络连接

虚拟私有云 (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_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_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_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_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公共访问-创建负载均衡器

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

所有的实例

示例图像

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密钥对

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-进行认证机构(CA)的配置和生成TLS证书的过程。

在这个过程中,我们将使用CloudFlare的PKI工具包cfssl来配置PKI基础设施。然后,我们将使用PKI基础设施创建认证机构,并生成admin、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管理员用户的客户端证书。

管理員用的客戶端證書

首先,生成管理员用的客户端证书和私钥。

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:node:”作为用户名,并在”system:nodes”组中进行认证。

在此步骤中,将为每个Kubernetes工作节点颁发满足节点授权者要求的证书和密钥。

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-controller-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(主题备用名称)列表中。

通过这个方法,外部客户也可以进行证书验证。

生成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控制器管理器使用密钥对来生成和签名服务账户的令牌。

发行服务帐户的证书和密钥。

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-生成用于认证的kubeconfig文件。

在该步骤中,Kubernetes API服务器会生成kubeconfigs(Kubernetes配置文件),以便配置和认证Kubernetes客户端。

客户认证设置

首先,生成conttoller-manager、kubelet、kube-proxy、scheduler以及管理员用户的kubeconfig文件。

Kubernetes的公共DNS地址 (Kubernetes de 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的节点授权器所认可。

为每个工作节点生成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

管理员用户的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}" \
    --output text --query 'Reservations[].Instances[].PublicIpAddress')

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

将 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

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

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

启动07-etcd

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连接。
(也就是说,在所有三个实例上都需要执行相同的命令)

使用tmux并行运行命令。

如果使用tmux,就能够轻松地在多个实例中同时执行命令。请查看这里。

etcd集群成员的启动

请注意,以下步骤需要在每个控制器实例中执行。

下载和安装etcd。

从GitHub上下载etcd的二进制文件。

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

创建systemd的unit文件,将其命名为etcd.service。

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-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
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-启动Kubernetes控制面板

在这个步骤中,我们将使用三个实例来创建高可用的Kubernetes控制平面。

另外,还需要创建外部负载均衡器来将Kubernetes API服务器公开给外部客户端。

在每个节点上安装Kubernetes API Server、Scheduler和Controller Manager组件。

先决条件

在这一步中,需要在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同时运行多个命令

使用tmux,您可以在多个实例中轻松同时运行命令。请参阅此链接。

Kubernetes控制平面的配置生成

创建一个存放Kubernetes配置文件的目录。

sudo mkdir -p /etc/kubernetes/config

Kubernetes控制器的二进制文件的下载和安装

下载Kubernetes官方的发行版二进制文件。

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"

安装已下载的二进制文件。

chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/

Kubernetes API服务器的配置

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/

参考: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调度程序的配置

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身份验证

在这个步骤中,我们将使用RBAC设置访问权限,使Kubernetes API服务器能够访问每个工作节点的Kubelet API。

要获取指标和日志信息,以及在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标志定义的客户端证书来对Kubelet进行身份验证,作为Kubernetes用户。

将kube-apiserver-to-kubelet的ClusterRole绑定给kubernetes用户。

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版本信息。

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-启动工作节点

在这一步中,我们将引导三个Kubernetes工作节点。

将下面的组件安装到每个节点上。

runc, gVisor, 容器网络插件, 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连接。(换句话说,需要在所有三个实例上执行相同的命令)

使用tmux并行运行命令。

如果使用tmux,您可以轻松地在多个实例中同时运行命令。请查看 这里。

Kubernetes工作节点的配置设置

安装所需的库。

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

socat是kubectl port-forward命令所必需的。

下载并安装工作人员的二进制文件。

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

我将创建一个桥接网络的设置文件。

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

我将创建一个回环网络的配置文件。

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 unit文件。

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代理的设置

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-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-0,worker-1和worker-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ネットワークの設定の所、何やってるかもう一度復習する必要あり

用于远程访问的kubectl配置文件-10

在这个步骤中,我们将基于admin用户的凭证生成kubectl命令行实用程序所需的kubeconfig文件。

在这一步中,请在与用于生成admin客户端证书的目录相同的目录中执行命令。

Kubernetes管理設定檔案

每个 kubeconfig 需要能够连接到 Kubernetes API 服务器。

为了实现高可用性,我们将使用分配给Kubernetes API服务器前的外部负载均衡器的IP地址。

创建适用于管理员用户身份验证的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

确认

确认远程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"}

获取远程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-配置集群内网络

在节点上调度的Pod将从节点的Pod CIDR范围中接收IP地址。

在这一时点上,由于找不到网络路径,该Pod无法与在不同节点上运行的其他Pod进行通信。

在此步骤中,我们将为每个工作节点创建路由,以将节点的Pod CIDR范围映射到节点的内部IP地址。

Kubernetes的网络模型实现还有其他选项。

路由表和路由集合

在这个部分,我们将收集在kubernetes-the-hard-way VPC网络内创建路由所需的信息。

通常情况下,这个功能由 flannel、calico、amazon-vpc-cni-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-DNS集群插件

在这个步骤中,因为说明和命令有所不一致,所以进行了修正。

在这个步骤中,我们将部署一个使用CoreDNS的DNS插件,为在Kubernetes集群中运行的应用程序提供基于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部署创建的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部署。

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

通过Busybox部署来检查创建的Pod。

kubectl get pod busybox

发挥能力

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

我将在busybox的Pod内执行对kubernetesservice的DNS查询。

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-烟雾测试 (13 –

在这个步骤中,我们执行任务来确认 Kubernetes 集群正常运行。

数据加密

在这个步骤中,我们将确认已保存数据的加密。

我会制作一个通用的秘密。

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

将存储在etcd中的kubernetes-the-hard-way的secret进行十六进制转储。

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作为前缀。

这表示aes-cbc提供程序使用加密密钥key1对数据进行了加密。

部署 – 在本地笔记本电脑上运行

在这一步中,我们要确认是否可以创建和管理部署。

我将创建一个Nginx web服务器的部署。

kubectl create deployment nginx --image=nginx

我们将检查由Nginx部署创建的Pod。

kubectl get pods -l app=nginx

发挥力量

NAME                     READY     STATUS    RESTARTS   AGE
nginx-65899c769f-xkfcn   1/1       Running   0          15s

端口转发

在这个步骤中,我们将使用端口转发来确认外部是否可以访问应用程序。

获取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

日志

在这一步中,我们将确认是否能够获取容器的日志。

展示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" "-"

执行

在这个步骤中,我们将确认是否能够在容器内执行命令。

进入nginx容器,运行nginx -v命令来显示nginx的版本。

kubectl exec -ti $POD_NAME -- nginx -v

施展能力

nginx version: nginx/1.17.3

服务

在这一步骤中,我们将确认是否可以通过使用Service来发布应用程序。

使用NodePort将nginx部署公开。

kubectl expose deployment nginx --port 80 --type NodePort

由于未设置云提供商集成,无法使用负载均衡器。

此步骤不包括云提供商集成的设置。

获取分配给nginx服务的节点端口。

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

不可信任的工作负载

我們將使用 gVisor 來驗證可以運行不受信任的載荷。

我将创建一个未受信任的Pod。

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)

使用gVisor的runsc命令,在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-crictl检查工作节点的镜像、Pod和容器。

登录工作节点并检查资源清单。
这个步骤可以在所有已启动的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-收拾干净

在这个步骤中,我们将删除之前创建的资源。

云计算中的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

网络连接

删除外部负载均衡器、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的学习。

广告
将在 10 秒后关闭
bannerAds