背景
接上一篇 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
- 安裝 acs-engine
- 一個可用的 Azure 中國區的賬號
步驟
- 通過 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:
- https://docs.microsoft.com/en-us/azure/service-fabric/
- https://docs.microsoft.com/en-us/azure/service-fabric-mesh/
- https://github.com/Azure/acs-engine
- https://github.com/Azure/azure-container-networking
- https://kubernetes.io/docs/concepts/storage/persistent-volumes/#expanding-persistent-volumes-claims
- https://github.com/Azure/acs-engine/blob/master/docs/kubernetes/features.md
- https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest
- https://github.com/Azure/acs-engine/releases
- https://docs.azure.cn/zh-cn/virtual-machines/linux/manage-availability
- https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/#adding-additional-entries-with-hostaliases