Azure Kubernetes 服务 (AKS)是微软云Azure上托管的Kubernetes 群集,可以用于快速部署Kubernetes 群集,结合Azure其它服务和功能,简化日常运维,轻松实现业务应用的弹性。本文是一个动手小实验,演示弹性部署的基本步骤。适用的场景是在AKS背后的虚拟机意外停机时,通过Kubernetes 的配置实现自动故障转移。

阅读本文需要掌握Kubernetes的基本知识和操作,以及AKS的基本概念部署

 

基本部署

应用

演示用的应用源码在这里

https://github.com/xfsnow/pipelines-javascript-docker/

请先fork到自己的GitHub账号下。

这个应用是个非常简单的Node.js 应用,用来输出时间和运行的主机名,用以演示负载均衡后具体运行在哪个后端上。主要文件只有一个

https://github.com/xfsnow/pipelines-javascript-docker/blob/a0aa063b97d6d6819c2adcdcea9b11e47959a86b/app/server.js#L19

输出内容就是下面这行:

res.send('Hello world! Now is '+now+'.\nRunning on '+os.hostname()+'.');

Kubernetes的部署文件主要是manifests/hello-deployment.yml,以 4 个replica部署一个deployment。这个配置文件的声明和作用都写在相关注释里了。核心原理是使用

# 通过 toleration 来检测节点状态,一旦发现节点不可用,则不再置放 pod

tolerations:

      - key: "node.kubernetes.io/unreachable"

        operator: "Exists"

        effect: "NoExecute"

        tolerationSeconds: 1

      - key: "node.kubernetes.io/not-ready"

        operator: "Exists"

        effect: "NoExecute"

        tolerationSeconds: 1

以及

  #健康检查,通过 httpGet 检查应用运行状态

          livenessProbe:

            httpGet:

              port: 80

              scheme: HTTP

              path: /

            # 初始化延迟 3 秒,用于应用首次启动时等待的时间,避免首次启动慢误判为失败。

            initialDelaySeconds: 10

            # 之后检查的间隔时间

            periodSeconds: 1

            # 超时多久认为是失败

            timeoutSeconds: 3

另有一个hello-service.yml,部署了一个负载均衡器,暴露出公网IP对外提供服务。这个负载均衡器也还有健康检查,在发现后端pod不可用时,会把其撤掉,然后再把新生成的pod挂载上来。

Azure资源

一个ACR,用于保存容器镜像,注意目前只有东2区域可以支持az acr build 命令在本地直接构建并推送到ACR。所以我们创建的ACR资源在东2区,而AKS集群可以在任何一个国内的区域。

# 定义环境变量

REGION_NAME=ChinaEast2

RESOURCE_GROUP=aksResilience

AKS_CLUSTER_NAME=aksResilience

ACR_NAME=acr$RANDOM

#创建资源组

az group create --location $REGION_NAME --name $RESOURCE_GROUP

# 创建ACR

az acr create --resource-group $RESOURCE_GROUP --name $ACR_NAME --location $REGION_NAME --sku Standard

列表看一下结果

az acr list -o table

NAME      RESOURCE GROUP    LOCATION     SKU    LOGIN SERVER         CREATION DATE         ADMIN ENABLED

--------  ----------------  -----------  -----  -------------------  --------------------  ---------------

acr11044  aksResilience     chinaeast2   Standard  acr11044.azurecr.cn  2021-02-05T03:12:36Z  False

 

#创建 AKS 集群

az aks create \

    --resource-group $RESOURCE_GROUP \

    --name $AKS_CLUSTER_NAME \

    --location $REGION_NAME \

    --node-count 2 \

    --enable-addons monitoring \

    --generate-ssh-keys

这步比较慢,请耐心等待,直到有返回结果。

列一下 AKS集群

az aks list -o table

Name           Location     ResourceGroup    KubernetesVersion    ProvisioningState    Fqdn

-------------  -----------  ---------------  -------------------  -------------------

aksResilience  chinanorth2  aksResilience    1.18.14              Succeeded  

# 把 ACR 绑定到AKS集群上,这样就可以自动验证从ACR拉取镜像到AKS集群了

az aks update \

    --name $AKS_CLUSTER_NAME \

    --resource-group $RESOURCE_GROUP \

    --attach-acr $ACR_NAME

这步比较慢,请耐心等待,直到有返回结果。

到此,Azure资源已创建完毕,总共1个AKS集群,包含1个虚拟机扩展集,其中有2台虚拟机。

列一下 AKS集群背后的虚拟机扩展集。注意这里的虚拟机扩展集由Azure自动创建在另一个资源组里。

az vmss list -o table

Name                         ResourceGroup                               Location     Zones    Capacity    Overprovision    UpgradePolicy

---------------------------  ------------------------------------------  -----------  -------  ----------  ---------------  ---------------

aks-nodepool1-40474697-vmss  MC_AKSRESILIENCE_AKSRESILIENCE_CHINANORTH2  chinanorth2           2           False            Manual

 

最后列一下虚拟机扩展集中的实例

az vmss list-instances \

>    -g MC_AKSRESILIENCE_AKSRESILIENCE_CHINANORTH2 \

>    -n aks-nodepool1-40474697-vmss \

>    -o table \

>    --query "[].{instanceId:instanceId, Name:name, State:provisioningState}"

InstanceId    Name                           State

------------  -----------------------------  ---------

0             aks-nodepool1-40474697-vmss_0  Succeeded

1             aks-nodepool1-40474697-vmss_1  Succeeded

部署Kubernetes

构建镜像推送到镜像注册表。

git clone https://github.com/xfsnow/pipelines-javascript-docker/

拉取源码。

先构建并推送镜像

cd app

az acr build \

    --resource-group $RESOURCE_GROUP \

    --registry $ACR_NAME \

    --image helloworld:1.0 .

 

然后获取镜像注册表具体的URL

az acr repository show -n $ACR_NAME --repository helloworld --query "registry"

"acr11044.azurecr.cn"

记下这个形如acr11044.azurecr.cn的URL,后面接上helloworld:1.0就是完整的镜像拉取地址,形如

acr11044.azurecr.cn/helloworld:1.0

cd manifests,

找到 hello-deployment.yml 中的这行

# 容器镜像使用 Azure 上的 ACR 服务。

          image: snowpeak.azurecr.cn/helloworld:1.3

替换成你自己的 ACR 镜像的URL “acr11044.azurecr.cn/helloworld:1.0”。

连接AKS集群并部署镜像

连接AKS集群

az aks get-credentials --resource-group $RESOURCE_GROUP --name $AKS_CLUSTER_NAME

先查看一下AKS集群中的节点

kubectl get nodes -o wide

NAME                                STATUS   ROLES   AGE    VERSION    INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUN

TIME

aks-nodepool1-40474697-vmss000000   Ready    agent   142m   v1.18.14   10.240.0.4    <none>        Ubuntu 18.04.5 LTS   5.4.0-1035-azure   docker://19.3

.14

aks-nodepool1-40474697-vmss000001   Ready    agent   142m   v1.18.14   10.240.0.5    <none>        Ubuntu 18.04.5 LTS   5.4.0-1035-azure   docker://19.3

.14

再看一下pod。

kubectl get pods -o wide

No resources found in default namespace.

此时尚未部署镜像,所以没有资源。

然后用  cd ../manifests/ 来到Kubernetes 配置文件目录下。

kubectl apply -f hello-deployment.yml和 kubectl apply -f hello-service.yml 部署到 AKS 集群中。部署好的集群初始是这样的。

kubectl get pods -o wide

NAME                          READY   STATUS    RESTARTS   AGE   IP           NODE                                NOMINATED NODE   READINESS GATES

helloworld-869d58f588-5tmpf   1/1     Running   0          71s   10.244.1.6   aks-nodepool1-40474697-vmss000001   <none>           <none>

helloworld-869d58f588-bt54r   1/1     Running   0          71s   10.244.1.7   aks-nodepool1-40474697-vmss000001   <none>           <none>

helloworld-869d58f588-qh6hn   1/1     Running   0          71s   10.244.0.6   aks-nodepool1-40474697-vmss000000   <none>           <none>

helloworld-869d58f588-w8xbx   1/1     Running   0          71s   10.244.0.7   aks-nodepool1-40474697-vmss000000   <none>           <none>

这是运行起来的4个pod,每个节点上2个pod。

kubectl get services

NAME         TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)        AGE

helloworld   LoadBalancer   10.0.116.133   139.217.112.135   80:30754/TCP   7d17h

 

这是部署起来的LoadBalancer,外网IP 139.217.112.135 可以直接访问,返回的结果如下:

curl http://139.217.112.135/;

Hello world! Now is 2021-02-04 08:26:52.924.

Running on helloworld-745c979464-q54vd.               

这里Running on helloworld-745c979464-q54vd. 正是上述1个pod的名称。

如果连续请求多次,会看到请求大致均匀地分发到4个后端pod上。

while(true); do   curl --connect-timeout 2 http://139.217.112.135/; echo -e '\n'; sleep 0.5; done

Hello world! Now is 2021-02-04 08:34:19.523.

Running on helloworld-745c979464-q54vd.

 

Hello world! Now is 2021-02-04 08:34:20.160.

Running on helloworld-745c979464-ljrcv.

 

Hello world! Now is 2021-02-04 08:34:20.798.

Running on helloworld-745c979464-97v26.

 

Hello world! Now is 2021-02-04 08:34:21.427.

Running on helloworld-745c979464-q54vd.

 

Hello world! Now is 2021-02-04 08:34:22.56.

Running on helloworld-745c979464-l2jpm.

 

Hello world! Now is 2021-02-04 08:34:22.697.

Running on helloworld-745c979464-ljrcv.

 

Hello world! Now is 2021-02-04 08:34:23.368.

Running on helloworld-745c979464-l2jpm.

 

Hello world! Now is 2021-02-04 08:34:24.6.

Running on helloworld-745c979464-ljrcv.

 

Hello world! Now is 2021-02-04 08:34:24.659.

Running on helloworld-745c979464-l2jpm.

模拟故障

我们手工停止一台虚拟机,模拟虚拟机发生故障的情况。

  1. 我们先打开实时观察 pod 运行状况

kubectl get po -o wide -w

 

  1. 再开一个新窗口运行

while(true); do   curl --connect-timeout 2 http://139.217.112.135/; echo -e '\n'; sleep 0.5; done

来看访问应用的情况

  1. 再开一个窗口执行停止一台虚拟机的命令

az vmss stop -g MC_DEMO_HELLOWORLD_CHINANORTH2 -n aks-agentpool-11798053-vmss --instance-id 0

  1. 回到第一个窗口,查看 pod 运行情况,看到类似如下的返回。

kubectl get po -o wide -w

NAME                         READY   STATUS        RESTARTS   AGE     IP             NODE                                NOMINATED NODE   READINESS GATES

helloworld-9bbdbf45b-2hnz4   1/1     Running       0          119s    10.240.0.152   aks-agentpool-11798053-vmss000001   <none>           <none>

helloworld-9bbdbf45b-64qt4   1/1     Terminating   0          6m41s   10.240.0.106   aks-agentpool-11798053-vmss000000   <none>           <none>

helloworld-9bbdbf45b-gczpn   1/1     Running       0          6m37s   10.240.0.135   aks-agentpool-11798053-vmss000001   <none>           <none>

helloworld-9bbdbf45b-l6dxm   1/1     Terminating   0          5m11s   10.240.0.68    aks-agentpool-11798053-vmss000000   <none>           <none>

helloworld-9bbdbf45b-rhn2m   1/1     Terminating   0          4m45s   10.240.0.42    aks-agentpool-11798053-vmss000000   <none>           <none>

helloworld-9bbdbf45b-smtft   1/1     Running       0          118s    10.240.0.185   aks-agentpool-11798053-vmss000001   <none>           <none>

helloworld-9bbdbf45b-tmdkr   1/1     Running       0          119s    10.240.0.149   aks-agentpool-11798053-vmss000001   <none>           <none>

第1个节点上的pod显示正在停止,而新的pod运行在第2个节点上。

  1. 再来到运行curl的窗口查看

while(true); do   curl --connect-timeout 2 http://139.217.112.135/; echo -e '\n'; sleep 0.5; done

curl: (28) Connection timed out after 2013 milliseconds

curl: (28) Connection timed out after 2009 milliseconds

 

Hello world! Now is 2021-02-04 01:40:37.752.

Running on helloworld-9bbdbf45b-2vjxt.

 

Hello world! Now is 2021-02-04 01:40:38.409.

Running on helloworld-9bbdbf45b-vpvn6.

 

Hello world! Now is 2021-02-04 01:40:39.57.

Running on helloworld-9bbdbf45b-2vjxt.

 

Hello world! Now is 2021-02-04 01:40:39.736.

 

在出现若干次超时后,返回结果恢复正常了,并且主机名出现了新的pod名称。

仔细查看输出内容的时间,可以看到超时经历的时间不超过1分钟。

  1. 最后我们再恢复节点运行

可以看到原来停止的节点上的pod显示为正常Terminating并最终消失,现有4个pod都运行在第2个节点上。可以通过设置replicas 来重新均衡置放pod。

资源清理

az group delete --name $RESOURCE_GROUP --yes

删除该资源组及其所有资源,实验结束。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐