AWS EKS 建立k8s生產環境範例

2022-08-04 06:03:17

#AWS EKS 建立k8s生產環境範例


  • 在AWS部署海外節點, 圖簡單使用web控制檯建立VPC和k8s叢集出錯(k8s), 使用cli命令列工具建立成功
  • 本範例為覆盤, 記錄aws命令列工具建立eks, 安裝efs驅動、LBS、ingress-nginx,使用ECR映象儲存等

#安裝命令列工具

#安裝aws cli
cd /tmp 
curl -kL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws --version
#設定aws key
aws configure
#檢視設定
aws configure list

#安裝kubectl
curl -o kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.22.6/2022-03-09/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv kubectl /usr/local/bin
kubectl version --short --client

#安裝eksctl
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin
eksctl version

#建立VPC網路和子網

#建立VPC網路和子網已單獨發帖
https://www.cnblogs.com/elvi/p/16542406.html

#建立k8s叢集

#env
k8s_name=aws-k8s
Region=ap-southeast-1 #新加坡 
#獲取aws賬戶id
OwnerId=$(aws ec2 describe-vpcs --region ${Region} |jq -r ".Vpcs[0].OwnerId")
#使用已有子網 
private-subnets-id="subnet-lan-a-xxx,subnet-lan-b-xxx"
public-subnets-id="subnet-public-a-xxx,subnet-public-b-xxx"
# k8s cluster 
eksctl create cluster \
 --region ${Region} \
 --name ${k8s_name} \
 --version 1.22 \
 --vpc-private-subnets ${private-subnets-id} \
 --vpc-public-subnets  ${public-subnets-id} \
 --managed \
 --without-nodegroup \
 --dry-run

# 檢視
eksctl get cluster --name ${k8s_name} --region ${Region}

# 出錯或不要了,可刪除
# eksctl delete cluster --name=${k8s_name}

# --dry-run 試執行,正式建立時去掉
# --without-nodegroup 不建立node節點
# --vpc-xx 新增已有網路,若不指定會自動建立
# 建議使用多個可用區網路,k8s叢集建立後無法更改
# eksctl create cluster --help #檢視幫助

#建立k8s計算節點組

#建立b區k8s節點
#k8s nodegroup  test
eksctl create nodegroup \
 --region ${Region} \
 --cluster ${k8s_name} \
 --name k8s-work-test  \
 --node-type m5.large \
 --nodes 1 \
 --nodes-min 1 \
 --nodes-max 10 \
 --instance-name test-node-b \
 --node-ami-family Ubuntu2004 \
 --node-private-networking \
 --node-zones ${Region}b \
 --node-security-groups sg-xxxxxxx \
 --ssh-access \
 --ssh-public-key aws-bastion \
 --full-ecr-access \
 --managed \
 --dry-run

# --nodes 1 建立1個node節點, 規格 m5.large 2核8G
# --node-ami-family Ubuntu2004 作業系統Ubuntu20.04
# --node-private-networking 使用私有子網
# --node-zones 可用區
# --node-security-groups 使用已建立的安全組
# --full-ecr-access ECR映象倉庫許可權,一定要
# eksctl create nodegroup --help #檢視幫助

#節點擴容
eksctl scale nodegroup --region ${Region} \
 --cluster ${k8s_name} --nodes=2 --name k8s-work-test

# 測試正常就可以刪除, 建立設定更高的正式節點
# delete node
# eksctl delete nodegroup --cluster=${k8s_name} --name=k8s-work-test

#建立b區正式節點組 
eksctl create nodegroup \
 --region ${Region} \
 --cluster ${k8s_name} \
 --name k8s-work-b  \
 --node-type m5.4xlarge \
 --nodes 2 \
 --nodes-min 1 \
 --nodes-max 10 \
 --instance-name k8s-node-b \
 --max-pods-per-node 110 \
 --node-ami-family Ubuntu2004 \
 --node-private-networking \
 --node-zones ${Region}b \
 --node-security-groups sg-xxxxxxx \
 --ssh-access \
 --ssh-public-key aws-bastion \
 --full-ecr-access \
 --external-dns-access \
 --managed \
 --dry-run

#規格m5.4xlarge 16核64G
#node-zones建立多區,可用於高可用

#為k8s叢集建立IAM OIDC提供商

# IAM OIDC即 AWS Identity and Access Management (IAM) OpenID Connect (OIDC)
# 建立IMA許可權角色時,需要此功能開啟  

#檢視是否有OIDC,沒有則建立
oidc_id=$(aws eks describe-cluster --name ${k8s_name} --query "cluster.identity.oidc.issuer" --output text |cut -d'/' -f 5)
if [ $(aws iam list-open-id-connect-providers | grep $oidc_id | wc -l ) -eq 0 ]; then
  eksctl utils associate-iam-oidc-provider --cluster ${k8s_name} --approve
fi

#eks安裝efs csi驅動

  • k8s使用AWS EFS儲存時用到csi驅動
  • efs可使用nfs協定掛載,但k8s節點預設沒安裝nfs使用者端
#建立IAM policy和角色
curl -o iam-policy-efs.json \
 https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/docs/iam-policy-example.json

aws iam create-policy \
    --policy-name EKS_EFS_CSI_Driver_Policy \
    --policy-document file://iam-policy-efs.json

#建立許可權
eksctl create iamserviceaccount \
  --cluster ${k8s_name} \
  --namespace kube-system \
  --name efs-csi-controller-sa \
  --attach-policy-arn arn:aws:iam::${OwnerId}:policy/EKS_EFS_CSI_Driver_Policy \
  --approve \
  --region ${Region}

# 更新kubeconfig  ~/.kube/config  
aws eks update-kubeconfig --region ${Region} --name ${k8s_name}

#下載yaml檔案
kubectl kustomize \
  "github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.4" > aws-eks-efs-csi.1.4.yaml

# vim aws-eks-efs-csi.1.4.yaml
# 手動刪除如下部分  
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-controller-sa
  namespace: kube-system
---

#部署efs csi
kubectl apply -f aws-eks-efs-csi.1.4.yaml
#使用efs建立pvc範例
apiVersion: v1
kind: PersistentVolume
metadata:
  name: aws-efs-test
spec:
  capacity:
    storage: 2000Gi
  accessModes: 
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-xxx:/data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: aws-efs-test
spec:
  accessModes: 
    - ReadWriteMany
  resources:
    requests:
      storage: 2000Gi

# fs-xxx 為efs範例id,需要單獨建立  
# 建立efs後需新增子網和安全組,否則無法存取  

#安裝AWS LB Controller

  • AWS LoadBalancer預設使用Classic Load Balancer模式
  • 使用NLB、ALB模式的負載均衡器,和繫結EIP(繫結固定IP),必須安裝LB controller
#建立IAM角色
curl -o iam_lbs_v2.4.2.json \
  https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.2/docs/install/iam_policy.json

aws iam create-policy \
  --policy-name iam_lbs_v2.4.2 \
  --policy-document file://iam_lbs_v2.4.2.json

eksctl create iamserviceaccount \
  --cluster=${k8s_name} \
  --namespace=kube-system \
  --name=aws-load-balancer-controller \
  --role-name "AmazonEKSLoadBalancerControllerRole" \
  --attach-policy-arn=arn:aws:iam::${OwnerId}:policy/iam_lbs_v2.4.2 \
  --approve

#安裝cert-manager
kubectl apply \
  --validate=false \
  -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml

#下載yaml
curl -Lo aws-load-balancer-controller_2.4.2.yaml \
  https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.2/v2_4_2_full.yaml

#更改k8s叢集名稱
sed -i.bak -e "s|your-cluster-name|${k8s_name}|" aws-load-balancer-controller_2.4.2.yaml

#手動刪除如下部分
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/name: aws-load-balancer-controller
  name: aws-load-balancer-controller
  namespace: kube-system
---

#部署lbs
kubectl apply -f aws-load-balancer-controller_2.4.2.yaml

#檢視
kubectl get deployment -n kube-system aws-load-balancer-controller

#安裝ingress-nginx-controller

#下載yaml
curl -o aws-ingress-nginx.nlb.v1.3.0.yml \
  https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/aws/deploy.yaml

#增加spec.ipFamilyPolicy: SingleStack
#修改LoadBalancer部分的Service如下
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    #負載均衡器自定義名稱
    service.beta.kubernetes.io/aws-load-balancer-name: k8s-ingress-slb
    #負載均衡 NLB模式
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
    #使用EIP,網際網路模式
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
    #public子網
    service.beta.kubernetes.io/aws-load-balancer-subnets: subnet-axxx, subnet-bxxx
    #彈性IP地址
    service.beta.kubernetes.io/aws-load-balancer-eip-allocations: eipalloc-axxx, eipalloc-bxxx
    #獲取使用者端真事IP
    service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: preserve_client_ip.enabled=true
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.3.0
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: LoadBalancer
  # externalTrafficPolicy: Local
  ipFamilyPolicy: SingleStack
  ipFamilies:
    - IPv4
  ports:
  - appProtocol: http
    name: http
    port: 80
    protocol: TCP
    targetPort: http
  - appProtocol: https
    name: https
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx

#部署
kubectl apply -f aws-ingress-nginx.nlb.v1.3.0.yml

#檢視,獲得得到EXTERNAL-IP地址 
kubectl get svc ingress-nginx-controller -n ingress-nginx

#ping測試EXTERNAL-IP地址ip是否為自己的EIP地址
ping k8s-ingress-slb-xxx.elb.${Region}.amazonaws.com

#存取測試
curl -I k8s-ingress-slb-xxx.elb.${Region}.amazonaws.com

#使用私有映象倉庫,並部署服務測試

#建立儲存庫nginx
aws ecr create-repository \
    --repository-name nginx \
    --region $Region

#登入儲存庫(快取的登入憑證有效期12小時)
aws ecr get-login-password --region $Region \
 | docker login --username AWS --password-stdin ${OwnerId}.dkr.ecr.${Region}.amazonaws.com

#下載公共映象, 改tag為私有儲存庫地址
docker pull public.ecr.aws/nginx/nginx:alpine
docker tag  public.ecr.aws/nginx/nginx:alpine \
  ${OwnerId}.dkr.ecr.${Region}.amazonaws.com/nginx:alpine

#push映象到新建的儲存庫
docker push ${OwnerId}.dkr.ecr.${Region}.amazonaws.com/nginx:alpine

#deploy test
kubectl create deployment nginx --port=80 \
 --image=${OwnerId}.dkr.ecr.${Region}.amazonaws.com/nginx:alpine

#檢視
kubectl get pod

#生命週期策略範例,保持5個映象版本(tag)
cat >aws-ecr-policy.json <<EOF
{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Keep only 3 image",
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 3
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}
EOF
#建立策略
aws ecr put-lifecycle-policy --region $Region \
  --repository-name nginx \
  --lifecycle-policy-text file://aws-ecr-policy.json 

#刪除清理pod
kubectl delete deploy/nginx

#刪除儲存庫
aws ecr delete-repository \
  --region $Region --force \
  --repository-name nginx
  • k8s有pull私有映象倉庫許可權,是因為建立引數--full-ecr-access
  • AWS ECR映象儲存服務不支援目錄,只能分別給每個映象建立儲存庫
  • aws ecr get-login-password生成的憑證有效期12小時,可使用定時任務每天登入2次解決

參考檔案