快速搭建 Windows Kubernetes

背景

接上一篇 Windows 应用容器 后,想要快速且便利的部署与管理它们,可以借助容器编排工具。对于 Windows 容器,在今天 Service Fabric 会是个更为成熟的选择,在业界有更多的实践案例。笔者未来可能会写几篇关于如何使用 Service Fabric 来实现 Windows 平台下的微服务实践。此次我们接着上篇的内容往下去快速搭建 Windows Kubernetes 环境。

ACS-Engine

Azure 团队为容器编排引擎提供了一个开源的部署工具 acs-engine , 它可以支持在 Azure 上快速部署 Swarm、DC\OS、 Kubernetes 集群,同时具备扩缩 Worker 节点、升级等等。这套工具的大体思路是,利用 Azure Infrastructure 服务的可描述性,声明计算 、存储、网络等服务,同时实现 Kubernetes 与 Azure 整合,从而达到利用一个工具快速部署管理 Kubernetes。和我们使用 Terraform 类似,只是 acs-engine 是一个和 Azure 集成更为紧密的一个工具,使得这个 Kubernetes 可以利用 Azure CNI 、LoadBalancer 以及云磁盘存储以及云文件存储。下图来源于 ACS-engine 官方说明:再提一提 Azure CNI,它是由 Azure 团队针基于 CNI 实现的容器网络技术,利用 Azure SDN 的能力,使得容器网络可以连接 Azure VNET。因此使用 Azure CNI 可以:

  • Kubernetes 的容器网络和 Azure VNet 在一个平面之上,不需要有 Overlay。
  • 同一 Azure VNet 下的虚机也可以直接与 Kubernetes 容器互通,不需要经过负载经衡器。这个可以解决我们在微服务场景下, K8S 里的容器要与 此K8S 集群之外的服务实例之间的通讯,例如我们有 dubbo 或 spring cloud 混合部署的场景。
  • 在网络传输效率和资源消耗上会比自己在 Azure 上搭一套使用 Flannel 的 Kubernetes 要好,按照笔者的测试能提升 20%~30%。

对于 acs-engine 除了能支持原生 Kubernetes 具备的特性,更多特性可以参考 [6] , 当然能也能支持 GPU 的机器

前提

步骤

  • 通过 Azure CLI 登录 Azure 中国,并且生成一个 Contributor 的操作身份给后续部署 K8S 时建立相关资源使用
az cloud set --name AzureChinaCloud
az login
az account set --subscription="${SUBSCRIPTION_ID}"
#下一行命令会生成一个 service principal, 需要记录 appId 以及 password 留做后续使用
az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/${SUBSCRIPTION_ID}"
  • 准备 acs-engine 的集群部署描述文件, 由于 json 文件不包含注释的语法,为了能更好的理解下面的某些字段信息,我还是用 # 作为注释符用于解释。当实际操作时请删除相关 # 行目。
{
  "apiVersion": "vlabs",
  # 部署区域
  "location": "chinanorth2",
  "properties": {
    "orchestratorProfile": {
    #指定编排引擎类型为 kubernetes 
      "orchestratorType": "Kubernetes",
      # 指定版本
      "orchestratorRelease": "1.11",
      "kubernetesConfig": {
        # 该 kubernetes 集群将激活 rbac
        "enableRbac": true,
        # 该 kubernetes 集群将使用 Azure CNI 作为容器网络实现
        "networkPolicy": "azure"
      }
    },
    #指定 master 节点信息
    "masterProfile": {
    # 此处为 1 个 master 节点,也可以声明为 3, 或者其奇数
      "count": 1,
      # 给定一个 DNS 前缀,用于声明此 K8S 服务在 azure 中国北二区的子域名。例如此处为: burn-k8s-11.chinanorth2.cloudapp.chinacloudapi.cn
      "dnsPrefix": "burn-k8s-11",
      # master 节点的型号
      "vmSize": "Standard_D3_v2"
    },
    # 指定 Node 节点列表,可以声明多个, 不同机型分别是多少台,分别用什么操作系统。包括使用可用性集来做高可用性保证,也能使用虚机扩展集
    "agentPoolProfiles": [
      {
        "name": "windowspool2",
        "count": 3,
        "vmSize": "Standard_D3_v2",
        "availabilityProfile": "AvailabilitySet",
        "osType": "Windows"
      }
    ],
    # 在 Windows Kubernetes 的环境里需要 master 仍为 Linux, 在 masterProfile 中未声明使用什么 OS, 默认是 Linux
    "linuxProfile": {
    #虚机登录用户名
      "adminUsername": "zhaw",
      "ssh": {
        "publicKeys": [
          {
          # 虚机登录使用的公钥
            "keyData": "ssh-rsa XXX"
          }
        ]
      }
    },
    # node 节点使用的 windows 登陆信息
    "windowsProfile": {
      "adminUsername": "azureuser",
      "adminPassword": "XXX",
      "windowsPublisher": "MicrosoftWindowsServer",
                        "windowsOffer": "WindowsServerSemiAnnual",
                        "windowsSku": "Datacenter-Core-1803-with-Containers-smalldisk"
    },
    "servicePrincipalProfile": {
    #前面生成 service principal 的 appID
      "clientId": "XXX",
      #前面生成 service principal 的 password
      "secret": "XXX"
    }
  }
}
  • 使用 acs-engine 根据上述描述文件生成 ARM 的部署文件
# 下面的命令将生成文件目录: _output/<dns_prefix>
acs-engine generate kubernetes.json
  • output/<dnsprefix>/kubeconfig 目录下会生成连接到此 k8s 的 kubeconfig 文件,我们只需要在本地安装 kubectl 就可以操作此集群,不需要连到 Master 节点上操作
  • 通过 azure CLI 创建一个资源管理库并在其中部署出 k8s
# 进入到生成的文件目录
cd _output/<dns_prefix>
# 创建资源管理库
az group create --name <GROUP_NAME> --location chinanorth2 
# 部署 k8s
az group deployment create -g <GROUP_NAME> --template-file azuredeploy.json --parameters azuredeploy.parameters.json --verbose
  • 部署完毕以后可以查看节点信息
$ kubectl --kubeconfig=kubeconfig.chinanorth2.json get node --show-labels
NAME                    STATUS    ROLES     AGE       VERSION   LABELS
35598k8s9000            Ready     <none>    1h        v1.11.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=Standard_D3_v2,beta.kubernetes.io/os=windows,failure-domain.beta.kubernetes.io/region=chinanorth2,failure-domain.beta.kubernetes.io/zone=0,kubernetes.io/hostname=35598k8s9000
35598k8s9001            Ready     <none>    1h        v1.11.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=Standard_D3_v2,beta.kubernetes.io/os=windows,failure-domain.beta.kubernetes.io/region=chinanorth2,failure-domain.beta.kubernetes.io/zone=0,kubernetes.io/hostname=35598k8s9001
35598k8s9002            Ready     <none>    1h        v1.11.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=Standard_D3_v2,beta.kubernetes.io/os=windows,failure-domain.beta.kubernetes.io/region=chinanorth2,failure-domain.beta.kubernetes.io/zone=1,kubernetes.io/hostname=35598k8s9002
k8s-master-35598902-0   Ready     master    1h        v1.11.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=Standard_D3_v2,beta.kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=chinanorth2,failure-domain.beta.kubernetes.io/zone=0,kubernetes.azure.com/cluster=wink8s,kubernetes.io/hostname=k8s-master-35598902-0,kubernetes.io/role=master
  • 因为这个环境是一个 Linux 混合 windows 的集群,所以在部署 container 的时候需要指定节点类型,好在 acs-engine 部署出来的集群节点上携带操作系统相关的 label beta.kubernetes.io/os=windows ,我们可以通过 yaml 文件中使用 nodeSelector来指定节点信息
apiVersion: v1
kind: Service
metadata:
  name: stdlogclientwin
  labels:
    app: stdlogclientwin
spec:
  ports:
  - port: 80
    name: http
  selector:
    app: stdlogclientwin
  type: LoadBalancer
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: stdlogclientwin
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: stdlogclientwin
        version: v1
    spec:
      containers:
      - name: stdlogclientwin
        image: burning1docker/stdlogclientwin:1803
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - name: hostsdir
          mountPath: "C:/Windows/System32/drivers/etc"
      nodeSelector:
        beta.kubernetes.io/os: windows
      initContainers:
      - name: init
        image: microsoft/windowsservercore:1803
        command:
        - powershell
        - "Add-Content"
        - "-Path"
        - "C:/Windows/System32/drivers/etc/hosts"
        - "-Value"
        - "\"127.0.0.1 foo.local\""
        volumeMounts:
        - name: hostsdir
          mountPath: "C:/Windows/System32/drivers/etc"
      volumes:
      - name: hostsdir
        emptyDir: {}
  • 从上面的示例文件中,我们发现有一个通过 init container + emptyDir 来替换 hosts 的一个做法,在 Linux 下可以用 HostAliases 来实现,目前 Kubernetes Windows 上还不支持。所以可以通过这种方式来实现。
  • 另外我们还发现节点还携带了关于可用性集相关的信息,所以我们还可以使用 pod anti-affinity 来把同一容器应用 Pod 平均部署到不同容错域,以防 Azure 物理故障时导致容器在某一时刻不可用,可参考如下示例:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: cpuloadv1
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: cpuload
        version: v1
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - cpuload
              topologyKey: failure-domain.beta.kubernetes.io/zone
      containers:
      - name: cpuload
        image: burning1docker/cpuload:V1  
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        resources:
          limits:
            cpu: "1"
          requests:
            cpu: 500m

提问😂

  • 如何对 acs-engine 部署好的 k8s 集群扩 node 节点?
  • 是否可以对 acs-engine 部署好的 k8s 降级?
  • 对 acs-engine 部署好的 k8s 使用 Service Type 为 ·LoadBalancer· 时, Azure LoadBalancer 的负载规则需要手动定义么?

下一篇: 解决 Prometheus 不能获取 Kubernetes 集群上 Windows 节点的 Metrics

Ref:

posted @ 2018-09-27 14:06  温酒伴青枫  阅读(6616)  评论(0编辑  收藏  举报