

 **協助改進此頁面** 

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

若要為本使用者指南貢獻內容，請點選每個頁面右側面板中的**在 GitHub 上編輯此頁面**連結。

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 將應用程式移轉至新的節點群組
<a name="migrate-stack"></a>

此主題會說明如何建立新的節點群組，將現有的應用程式從容遷移至新群組，接著從叢集移除舊的節點群組。您可以使用 `eksctl` 或 AWS 管理主控台遷移至新的節點群組。
+  [`eksctl`](#eksctl_migrate_apps) 
+  [AWS 管理主控台 和 AWS CLI](#console_migrate_apps) 

## `eksctl`
<a name="eksctl_migrate_apps"></a>

 **使用 `eksctl` 將應用程式移轉至新的節點群組** 

如需有關將 eksctl 用於移轉的詳細資訊，請參閱 `eksctl` 文件中的[未受管的節點群組](https://eksctl.io/usage/nodegroup-unmanaged/)。

此程序需要 `eksctl` 版本 `0.215.0` 或更新版本。您可使用以下命令檢查您的版本：

```
eksctl version
```

如需有關安裝或更新 `eksctl` 的指示，請參閱 `eksctl` 文件中的 [Installation](https://eksctl.io/installation) 一節。

**注意**  
此程序只適用於使用 `eksctl` 所建立的叢集和節點群組。

1. 擷取現有節點群組的名稱，使用叢集名稱取代 *my-cluster*。

   ```
   eksctl get nodegroups --cluster=my-cluster
   ```

   範例輸出如下。

   ```
   CLUSTER      NODEGROUP          CREATED               MIN SIZE      MAX SIZE     DESIRED CAPACITY     INSTANCE TYPE     IMAGE ID
   default      standard-nodes   2019-05-01T22:26:58Z  1             4            3                    t3.medium         ami-05a71d034119ffc12
   ```

1. 使用以下命令啟動具備 `eksctl` 的新節點群組。在命令中，使用您自己的值取代每一個*範例值*。版本編號不能晚於控制平面的 Kubernetes 版本。也不能比控制平面的 Kubernetes 版本早兩個以上的次要版本。建議使用與控制平面相同的版本。

   如果下列條件為真，我們建議封鎖 Pod 對 IMDS 的存取：
   + 您計劃將 IAM 角色指派給您的所有 Kubernetes 服務帳戶，以便 Pod 僅具有所需的最低許可。
   + 叢集中沒有任何 Pod 因其他原因需要存取 Amazon EC2 執行個體中繼資料服務 (IMDS)，例如擷取目前 AWS 區域。

     如需詳細資訊，請參閱[‬限制存取指派給工作節點的執行個體設定檔‭](https://aws.github.io/aws-eks-best-practices/security/docs/iam/#restrict-access-to-the-instance-profile-assigned-to-the-worker-node)。

     若要封鎖 Pod 對 IMDS 的存取，請將 `--disable-pod-imds` 選項新增至下列命令。
**注意**  
如需更多可用旗標及其描述的資訊，請參閱 https://eksctl.io/。

   ```
   eksctl create nodegroup \
     --cluster my-cluster \
     --version 1.35 \
     --name standard-nodes-new \
     --node-type t3.medium \
     --nodes 3 \
     --nodes-min 1 \
     --nodes-max 4 \
     --managed=false
   ```

1. 之前的命令完成時，使用下列命令來確認所有節點已達到 `Ready` 狀態：

   ```
   kubectl get nodes
   ```

1. 使用下列命令來刪除原始的節點群組。在命令中，使用您的叢集和節點群組名稱取代每一個*範例值*：

   ```
   eksctl delete nodegroup --cluster my-cluster --name standard-nodes-old
   ```

## AWS 管理主控台 和 AWS CLI
<a name="console_migrate_apps"></a>

 **使用 AWS 管理主控台 和 AWS CLI 將應用程式遷移至新的節點群組** 

1. 依照[建立自我管理的 Amazon Linux 節點](launch-workers.md)中概述的步驟啟動新的節點群組。

1. 當當堆疊已完成建立時，從主控台將其選取，然後選擇 **Outputs (輸出)**。

1.  為已建立的節點群組記錄 **NodeInstanceRole**。您需要這樣才能新增 Amazon EKS 節點至叢集。
**注意**  
如果已將任何額外的 IAM 政策連接至舊節點群組 IAM 角色，則請將相同政策連接至新節點群組 IAM 角色，以便在新群組維持該功能。例如，如果為 Kubernetes [Cluster Autoscaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler) 新增許可，則適用此操作。

1. 更新兩個節點群組的安全群組，使其能夠互相通訊。如需詳細資訊，請參閱[檢視叢集的 Amazon EKS 安全群組要求](sec-group-reqs.md)。

   1. 記錄兩個節點群組的安全群組 ID。這在 AWS CloudFormation 堆疊輸出中顯示為 **NodeSecurityGroup** 值。

      您可以使用下列 AWS CLI 命令，從堆疊名稱取得安全群組 IDs。在這些命令中， `oldNodes`是舊版節點堆疊的 AWS CloudFormation 堆疊名稱，而 `newNodes`是您要遷移至的堆疊名稱。使用您自己的值取代每一個*範例值*。

      ```
      oldNodes="old_node_CFN_stack_name"
      newNodes="new_node_CFN_stack_name"
      
      oldSecGroup=$(aws cloudformation describe-stack-resources --stack-name $oldNodes \
      --query 'StackResources[?ResourceType==`AWS::EC2::SecurityGroup`].PhysicalResourceId' \
      --output text)
      newSecGroup=$(aws cloudformation describe-stack-resources --stack-name $newNodes \
      --query 'StackResources[?ResourceType==`AWS::EC2::SecurityGroup`].PhysicalResourceId' \
      --output text)
      ```

   1. 新增輸入規則至每個節點安全群組，使其接受彼此的流量。

      下列 AWS CLI 命令會將傳入規則新增至每個安全群組，以允許來自其他安全群組的所有通訊協定上的所有流量。此組態可讓每個節點群組中的 Pod 在您將工作負載移轉至新群組時互相通訊。

      ```
      aws ec2 authorize-security-group-ingress --group-id $oldSecGroup \
      --source-group $newSecGroup --protocol -1
      aws ec2 authorize-security-group-ingress --group-id $newSecGroup \
      --source-group $oldSecGroup --protocol -1
      ```

1. 編輯 `aws-auth` configmap 以在 RBAC 中對應新的節點執行個體角色。

   ```
   kubectl edit configmap -n kube-system aws-auth
   ```

   為新節點群組新增 `mapRoles` 項目。

   ```
   apiVersion: v1
   data:
     mapRoles: |
       - rolearn: ARN of instance role (not instance profile)
         username: system:node:{{EC2PrivateDNSName}}
         groups:
           - system:bootstrappers
           - system:nodes>
       - rolearn: arn:aws: iam::111122223333:role/nodes-1-16-NodeInstanceRole-U11V27W93CX5
         username: system:node:{{EC2PrivateDNSName}}
         groups:
           - system:bootstrappers
           - system:nodes
   ```

   使用您在[上一個步驟](#node-instance-role-step)中記錄的 **NodeInstanceRole** 值來取代*執行個體角色 ARN (非執行個體設定檔)* 程式碼片段。接著，儲存並關閉檔案以套用更新的 configmap。

1. 注意節點狀態並等待新的節點加入叢集和達到 `Ready` 狀態。

   ```
   kubectl get nodes --watch
   ```

1. (選用) 如果您使用的是 [Kubernetes Cluster Autoscaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler)，請將部署縮減為零 (0) 個複本以避免衝突的擴展動作。

   ```
   kubectl scale deployments/cluster-autoscaler --replicas=0 -n kube-system
   ```

1. 使用以下命令污染每個您想要用 `NoSchedule` 移除的節點。這樣就不會在您要取代的節點上排程或重新排程新的 Pod。如需詳細資訊，請參閱 Kubernetes 文件中的[污點和容差](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)。

   ```
   kubectl taint nodes node_name key=value:NoSchedule
   ```

   如果要將節點升級至新的 Kubernetes 版本，您可以使用以下程式碼片段識別並標示特定 Kubernetes 版本 (在此情況下為 `1.33`) 的所有節點。版本編號不能晚於控制平面的 Kubernetes 版本。也不能比控制平面的 Kubernetes 版本早兩個以上的次要版本。建議使用與控制平面相同的版本。

   ```
   K8S_VERSION=1.33
   nodes=$(kubectl get nodes -o jsonpath="{.items[?(@.status.nodeInfo.kubeletVersion==\"v$K8S_VERSION\")].metadata.name}")
   for node in ${nodes[@]}
   do
       echo "Tainting $node"
       kubectl taint nodes $node key=value:NoSchedule
   done
   ```

1.  判斷叢集的 DNS 提供商。

   ```
   kubectl get deployments -l k8s-app=kube-dns -n kube-system
   ```

   範例輸出如下。此叢集針對 DNS 解析度使用 CoreDNS，但您的叢集可能會傳回 `kube-dns`：

   ```
   NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
   coredns   1         1         1            1           31m
   ```

1. 如果您目前的部署執行少於 2 個複本，請將部署擴增為 2 個複本。如果您先前的命令輸出傳回該項目，請以 `kubedns` 取代 *coredns*。

   ```
   kubectl scale deployments/coredns --replicas=2 -n kube-system
   ```

1. 使用以下命令清空您想要從叢集移除的每個節點：

   ```
   kubectl drain node_name --ignore-daemonsets --delete-local-data
   ```

   如果您要將節點升級至新的 Kubernetes 版本，請使用下列程式碼片段識別並耗盡特定 Kubernetes 版本 （在本例中為 *1.33*) 的所有節點。

   ```
   K8S_VERSION=1.33
   nodes=$(kubectl get nodes -o jsonpath="{.items[?(@.status.nodeInfo.kubeletVersion==\"v$K8S_VERSION\")].metadata.name}")
   for node in ${nodes[@]}
   do
       echo "Draining $node"
       kubectl drain $node --ignore-daemonsets --delete-local-data
   done
   ```

1. 在舊的節點完成消耗後，請撤銷您先前授權的安全群組傳入規則。然後，刪除 AWS CloudFormation 堆疊以終止執行個體。
**注意**  
如果您將任何其他 IAM 政策連接至舊節點群組 IAM 角色，例如新增 [Kubernetes Cluster Autoscaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler) 的許可，請先從角色分離這些其他政策，然後才能刪除 AWS CloudFormation 堆疊。

   1. 撤銷您先前為節點安全群組建立的傳入規則。在這些命令中， `oldNodes`是舊版節點堆疊的 AWS CloudFormation 堆疊名稱，而 `newNodes`是您要遷移至的堆疊名稱。

      ```
      oldNodes="old_node_CFN_stack_name"
      newNodes="new_node_CFN_stack_name"
      
      oldSecGroup=$(aws cloudformation describe-stack-resources --stack-name $oldNodes \
      --query 'StackResources[?ResourceType==`AWS::EC2::SecurityGroup`].PhysicalResourceId' \
      --output text)
      newSecGroup=$(aws cloudformation describe-stack-resources --stack-name $newNodes \
      --query 'StackResources[?ResourceType==`AWS::EC2::SecurityGroup`].PhysicalResourceId' \
      --output text)
      aws ec2 revoke-security-group-ingress --group-id $oldSecGroup \
      --source-group $newSecGroup --protocol -1
      aws ec2 revoke-security-group-ingress --group-id $newSecGroup \
      --source-group $oldSecGroup --protocol -1
      ```

   1. 開啟 [AWS CloudFormation 主控台](https://console.aws.amazon.com/cloudformation/)。

   1. 選取舊的節點堆疊。

   1. 選擇 **刪除**。

   1. 在 **Delete stack** (刪除堆疊) 確認對話方塊中，選擇 **Delete stack** (刪除堆疊)。

1. 編輯 `aws-auth` configmap 以從 RBAC 移除舊的節點執行個體角色。

   ```
   kubectl edit configmap -n kube-system aws-auth
   ```

   刪除舊節點群組的 `mapRoles` 項目。

   ```
   apiVersion: v1
   data:
     mapRoles: |
       - rolearn: arn:aws: iam::111122223333:role/nodes-1-16-NodeInstanceRole-W70725MZQFF8
         username: system:node:{{EC2PrivateDNSName}}
         groups:
           - system:bootstrappers
           - system:nodes
       - rolearn: arn:aws: iam::111122223333:role/nodes-1-15-NodeInstanceRole-U11V27W93CX5
         username: system:node:{{EC2PrivateDNSName}}
         groups:
           - system:bootstrappers
           - system:nodes>
   ```

   儲存並關閉檔案以套用更新的 configmap。

1. (選用) 如果您使用的是 Kubernetes [Cluster Autoscaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler)，請將部署縮減回 1 個複本。
**注意**  
您也必須適當標記新的 Auto Scaling 群組 (例如 `k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/my-cluster`)，並更新 Cluster Autoscaler 部署的命令，以指向新標記的 Auto Scaling 群組。如需詳細資訊，請參閱 [Cluster Autoscaler on AWS](https://github.com/kubernetes/autoscaler/tree/cluster-autoscaler-release-1.3/cluster-autoscaler/cloudprovider/aws)。

   ```
   kubectl scale deployments/cluster-autoscaler --replicas=1 -n kube-system
   ```

1. (選用) 確認您使用的是最新版本的 [Kubernetes 專用 Amazon VPC CNI 外掛程式](https://github.com/aws/amazon-vpc-cni-k8s)。您可能需要更新 CNI 版本，才能使用最新支援的執行個體類型。如需詳細資訊，請參閱[使用 Amazon VPC CNI 將 IP 指派給 Pod](managing-vpc-cni.md)。

1. 如果您的叢集針對 DNS 解析度使用 `kube-dns` (請參閱 [[migrate-determine-dns-step]](#migrate-determine-dns-step))，請將 `kube-dns` 部署縮減至一個複本。

   ```
   kubectl scale deployments/kube-dns --replicas=1 -n kube-system
   ```