本文來自Rancher Labs前端
在Kubernetes 1.14版本中已經GA了對Windows的支持。這一結果凝結了一羣優秀的工程師的努力,他們來自微軟、Pivotal、VMware、紅帽以及如今已經關閉的Apprenda等幾家公司。我在Apprenda工做時,不定時會爲sig-windows社區作出一些貢獻。即使如今在Rancher Labs任職,也一直關注它的動向。因此當公司決定在Rancher中增長對Windows支持時,我極爲興奮。node
Rancher 2.3已於本月月初發布,這是首個GA支持Windows容器的Kubernetes管理平臺。它極大下降了企業使用Windows容器的複雜性,併爲基於Windows遺留應用程序的現代化提供快捷的途徑——不管這些程序是在本地運行仍是在多雲環境中運行。此外,Rancher 2.3還能夠將它們容器化並將其轉換爲高效、安全和可遷移的多雲應用程序,從而省去重寫應用程序的工做。linux
在本文中,咱們將在運行RKE的Kubernetes集羣之上配置Rancher集羣。咱們也將會配置同時支持Linux和Windows容器的集羣。完成配置後,咱們將聊聊操做系統的定位,由於Kubernetes scheduler須要指導各類Linux和Windows容器在啓動時的部署位置。android
咱們的目標是以徹底自動化的方式執行這一操做。因爲Rancher 2.3目前還沒有stable,所以這沒法在生產環境中使用,但若是你正須要使用Azure和Rancher來完成基礎架構自動化,那麼這對大家的團隊而言將會是一個良好的開端。退一萬步而言,即便你不使用Azure,在本例中的許多概念和代碼均可以應用於其餘環境中。nginx
在咱們正式開始以前,我須要告知你許多注意事項和「陷阱」。首先,最顯而易見的就是:Windows不是Linux。Windows新增了支持網絡網格中的容器化應用程序所需的子系統,它們是Windows操做系統專有的,由Windows主機網絡服務和Windows主機計算服務實現。操做系統以及底層容器運行時的配置、故障排除以及運維維護將會有顯著區別。並且,Windows節點收到Windows Server licensing的約束,容器鏡像也受Windows容器的補充許可條款的約束。git
WindowsOS版本須要綁定到特定的容器鏡像版本,這是Windows獨有的。使用Hyper-V隔離能夠克服這一問題,可是從Kubernetes 1.16開始,Kubernetes不支持Hyper-V隔離。所以,Kubernetes和Rancher僅能在Windows Server 1809/Windows Server 2019以及Windows Server containers Builds 17763 以及Docker EE-basic 18.09以前的版本中運行。github
Kubernetes 1.16版本以來,CSI插件支持alpha版本。Windows節點支持大量的in-tree和flex volume。docker
Rancher 支持僅限於flannel提供的主機網關(L2Bridge)和VXLAN(Overlay)網絡支持。在咱們的方案中,咱們將利用默認的VXLAN,由於當節點並不都在同一個網絡上時,主機網關選項須要User Defined Routes配置。這取決於提供商,因此咱們將利用VXLAN功能的簡單性。根據Kubernetes文檔,這是alpha級別的支持。當前沒有支持Kubernetes網絡策略API的開源Windows網絡插件。bootstrap
請確保你已經閱讀了Kubernetes文檔,由於在Windows容器中有許多功能沒法實現,或者其功能和Linux中的相同功能實現方式有所不一樣。windows
Kubernetes文檔:
https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/#limitations
自動化是實現DevOps的第一種方式。咱們將自動化咱們的Rancher集羣和要在該集羣中配置的Azure節點的基礎架構。
Terraform是一個開源的基礎架構自動化編排工具,它幾乎支持全部市面上能見到的雲服務提供商。今天咱們將使用這一工具來自動化配置。確保你運行的Terraform版本至少是Terraform 12。在本文中,使用Terraform 版本是v0.12.9。
$ terraform version
Terraform v0.12.9複製代碼
用於Terraform 的RKE provider是一個社區項目,並不是由Rancher官方進行研發的,但包括我在內的Rancher的不少工程師都在使用。由於這是一個社區provider而不是Terraform官方的provider,所以你須要安裝最新版本到你的Terraform插件目錄中。對於大部分的Linux發行版來講,你可使用本文資源庫中包含的setup-rke-terraform-provider.sh
腳本。
用於Terraform的Rancher2 provider是Terraform支持的provider,它經過Rancher REST API來自動化Rancher。咱們將用它從Terraform的虛擬機中建立Kubernetes集羣,這一虛擬機須要使用Azure Resource Manager和Azure Active Directory Terraform Provider進行建立。
本文中的Terraform模型的每一個步驟都會被拆分紅子模型,這將加強模型可靠性而且未來若是你建立了其餘自動化架構,這些模型均可以從新使用。
Azure Resource Manager和Azure Active Directory Terraform Provider將使用一個激活的Azure Cli登陸以訪問Azure。他們可使用其餘認證方法,但在本例中,我在運行Terraform以前先登陸。
az login
Note, we have launched a browser for you to login. For old experience with device code, use "az login --use-device-code"
You have logged in. Now let us find all the subscriptions to which you have access...
[
{
"cloudName": "AzureCloud",
"id": "14a619f7-a887-4635-8647-d8f46f92eaac",
"isDefault": true,
"name": "Rancher Labs Shared",
"state": "Enabled",
"tenantId": "abb5adde-bee8-4821-8b03-e63efdc7701c",
"user": {
"name": "jvb@rancher.com",
"type": "user"
}
}
]複製代碼
Azure Resource Group是Rancher集羣的節點和其餘虛擬硬件存儲的位置範圍。咱們實際上將會建立兩個組,一個用於Rancher集羣,另外一個用於Kubernetes集羣。那將在resource-group module
中完成。
https://github.com/JasonvanBrackel/cattle-drive/tree/master/terraform-module/resourcegroup-module
resource "azurerm_resource_group" "resource-group" {
name = var.group-name
location = var.region
}複製代碼
虛擬網絡
咱們將須要一個虛擬網絡和子網。咱們將使用network-module
在各自的資源組中分別設置它們。
咱們將使用node-module設置每一個節點。既然每一個節點都須要安裝Docker,那麼咱們在使用Rancher install-docker腳本配置和安裝Docker時,咱們須要運行cloud-init文件。這個腳本將檢測Linux發行版而且安裝Docker。
os_profile {
computer_name = "${local.prefix}-${count.index}-vm"
admin_username = var.node-definition.admin-username
custom_data = templatefile("./cloud-init.template", { docker-version = var.node-definition.docker-version, admin-username = var.node-definition.admin-username, additionalCommand = "${var.commandToExecute} --address ${azurerm_public_ip.publicIp[count.index].ip_address} --internal-address ${azurerm_network_interface.nic[count.index].ip_configuration[0].private_ip_address}" })
}複製代碼
```
#cloud-config
repo_update: true
repo_upgrade: all複製代碼
runcmd:
模板中的附加命令塊用這些節點的sleep 0填充,可是稍後該命令將用於Linux節點,以將Rancher管理的自定義集羣節點加入平臺。
**設置節點**
接下來,咱們將爲每一個角色建立幾組節點:控制平面、etcd和worker。咱們須要考慮幾件事,由於Azure處理其虛擬網絡的方式有一些獨特之處。它會保留前幾個IP供本身使用,所以在建立靜態IP時須要考慮這一特性。這就是在NIC建立中的4個IP,因爲咱們也管理子網的IP,所以咱們在每一個IP中都進行了處理。
複製代碼
resource "azurermnetworkinterface" "nic" {count = var.node-countname = "${local.prefix}-${count.index}-nic"location = var.resource-group.locationresourcegroupname = var.resource-group.name
ip_configuration {name = "${local.prefix}-ip-config-${count.index}"subnet_id = var.subnet-idprivateipaddress_allocation = "static"privateipaddress = cidrhost("10.0.1.0/24", count.index + var.address-starting-index + 4)publicipaddressid = azurermpublic_ip.publicIp[count.index].id}}
## 爲何不對私有IP使用動態分配?
在建立並徹底配置節點以前,Azure的Terraform provider將沒法獲取IP地址。而經過靜態處理,咱們能夠在生成RKE集羣期間使用地址。固然,還有其餘方法也能解決這一問題,如將基礎架構配置分紅多個來運行。可是爲簡單起見,仍是對IP地址進行靜態管理。
**設置前端負載均衡器**
默認狀況下,Rancher安裝程序將會在每一個worker節點安裝一個ingress controller,這意味着咱們應該在可用的worker節點之間負載均衡任何流量。咱們也將會利用Azure的功能來爲公共IP建立一個公共的DNS入口,而且將其用於集羣。這能夠在`loadbalancer-module`中完成。
https://github.com/JasonvanBrackel/cattle-drive/tree/master/terraform-module/loadbalancer-module
複製代碼
resource "azurermpublicip" "frontendloadbalancer_publicip" {name = "rke-lb-publicip"location = var.resource-group.locationresourcegroupname = var.resource-group.nameallocation_method = "Static"domainnamelabel = replace(var.domain-name-label, ".", "-")}
做爲替代方案,其中包含使用cloudflare DNS的代碼。咱們在這篇文章中沒有使用這一方案,可是你能夠不妨一試。若是你使用這個方法,你將須要重置DNS緩存或主機文件入口,以便你的本地計算機能夠調用Rancher來使用Rancher terraform provider。
複製代碼
provider "cloudflare" {email = "${var.cloudflare-email}"api_key = "${var.cloudflare-token}"}
data "cloudflare_zones" "zones" {filter {name = "${replace(var.domain-name, ".com", "")}.*" # Modify for other suffixesstatus = "active"paused = false}}
resource "cloudflare_record" "domain" {zoneid = data.cloudflarezones.zones.zones[0].idname = var.domain-namevalue = var.ip-addresstype = "A"ttl = "120"proxied = "false"}
**使用RKE安裝Kubernetes**
咱們將使用Azure和Terraform的動態代碼塊建立的節點與開源RKE Terraform Provider來建立一個RKE集羣。
複製代碼
dynamic nodes {for_each = module.rancher-control.nodescontent {address = module.rancher-control.publicIps[nodes.key].ip_addressinternaladdress = module.rancher-control.privateIps[nodes.key].privateip_addressuser = module.rancher-control.node-definition.admin-usernamerole = ["controlplane"]ssh_key = file(module.rancher-control.node-definition.ssh-keypath-private)}}
## 使用RKE安裝Tiller
有不少種方式能夠安裝Tiller,你可使用Rancher官方文檔中的方法,可是在本教程中咱們將利用RKE Add-On的特性。
官方文檔:
https://rancher.com/docs/rancher/v2.x/en/installation/ha/helm-init/
複製代碼
kind: ServiceAccountapiVersion: v1metadata:name: tiller
kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:name: tillernamespace: kube-systemsubjects:
**初始化Helm**
Terraform能夠運行本地腳本。既然咱們將要使用Helm來安裝`cert-manager`和Rancher,咱們須要初始化Helm。
**安裝cert-manager**
這一步和Rancher文檔中【使用Tiller安裝cert-manager】的內容同樣。
https://rancher.com/docs/rancher/v2.x/en/installation/ha/helm-rancher/#let-s-encrypt
複製代碼
resource "null_resource" "install-cert-manager" {dependson = [nullresource.initialize-helm]provisioner "local-exec" {command = file("../install-cert-manager.sh")}}
**安裝Rancher**
這一步和官方文檔中【安裝Rancher】的內容同樣。
https://rancher.com/docs/rancher/v2.x/en/installation/ha/helm-rancher/
install-rancher腳本有不少個版本,咱們所使用的版本要求要有Let’s Encrypt的證書。若是你更習慣使用自簽名的證書,你須要將i`nstall-rancher.sh`的symlink更改成指向其餘版本,並從下面的示例代碼中刪除let-encrypt變量。
複製代碼
resource "null_resource" "install-rancher" {dependson = [nullresource.install-cert-manager]provisioner "local-exec" {command = templatefile("../install-rancher.sh", { lets-encrypt-email = var.lets-encrypt-email, lets-encrypt-environment = var.lets-encrypt-environment, rancher-domain-name = local.domain-name })}}
**Rancher引導程序**
Terraform的Rancher2 Provider包含了一個引導模式。這容許咱們能夠設置一個admin密碼。你能夠在`rancherbootstrap-module`中看到這一步。
複製代碼
provider "rancher2" {alias = "bootstrap"
api_url = var.rancher-urlbootstrap = true
insecure = true}
resource "rancher2_bootstrap" "admin" {provider = rancher2.bootstrappassword = var.admin-passwordtelemetry = true}
咱們在這裏設置集羣url。
複製代碼
provider "rancher2" {alias = "admin"
apiurl = rancher2bootstrap.admin.urltokenkey = rancher2bootstrap.admin.token
insecure = true}
resource "rancher2_setting" "url" {provider = rancher2.adminname = "server-url"value = var.rancher-url}
# Part2:設置Rancher管理的Kubernetes集羣
## 爲Azure建立服務主體
在咱們可使用Azure cloud來建立Load Balancer 服務和Azure存儲以前,咱們須要先爲Cloud Controller Manager配置connector。所以,咱們在cluster-module和serviceprincipal-module中建立了一個服務主體,其做用域爲集羣的Resource Group。
複製代碼
resource "azuread_application" "ad-application" {name = var.application-namehomepage = "https://${var.application-name}"identifier_uris = ["http://${var.application-name}"]availabletoother_tenants = false}
resource "azureadserviceprincipal" "service-principal" {applicationid = azureadapplication.ad-application.application_idapproleassignment_required = true}
resource "azurermroleassignment" "serviceprincipal-role" {scope = var.resource-group-idroledefinitionname = "Contributor"principalid = azureadservice_principal.service-principal.id}
resource "random_string" "random" {length = 32special = true}
resource "azureadserviceprincipal_password" "service-principal-password" {serviceprincipalid = azureadserviceprincipal.service-principal.idvalue = random_string.random.resultend_date = timeadd(timestamp(), "720h")}
## 定義自定義集羣
咱們須要設置flannel 網絡選項以支持Windows flannel驅動。你將會注意到Azure provider的配置。
複製代碼
resource "rancher2_cluster" "manager" {name = var.cluster-namedescription = "Hybrid cluster with Windows and Linux workloads"
rke_config {network {plugin = "flannel"options = {flannelbackendport = 4789flannelbackendtype = "vxlan"flannelbackendvni = 4096}}cloud_provider {azurecloudprovider {aadclientid = var.service-principal.client-idaadclientsecret = var.service-principal.client-secretsubscription_id = var.service-principal.subscription-idtenant_id = var.service-principal.tenant-id}}}}
## 建立虛擬機
這些虛擬機的建立過程與早期計算機相同,而且包含Docker安裝腳本。這裏惟一的改變是使用來自以前建立集羣的linux節點命令的附加命令。
複製代碼
module "k8s-worker" {source = "./node-module"prefix = "worker"
resource-group = module.k8s-resource-group.resource-groupnode-count = var.k8s-worker-node-countsubnet-id = module.k8s-network.subnet-idaddress-starting-index = var.k8s-etcd-node-count + var.k8s-controlplane-node-countnode-definition = local.node-definitioncommandToExecute = "${module.cluster-module.linux-node-command} --worker"}
## 建立Windows Workers
Windows worker進程相似於Linux進程,但有一些例外。因爲Windows不支持cloud-init文件,咱們須要建立一個Windows自定義腳本擴展。你能夠在windowsnode-module中看到它:
https://github.com/JasonvanBrackel/cattle-drive/tree/master/terraform-module/windowsnode-module
Windows worker使用密碼進行認證,還須要VM Agent來運行自定義腳本擴展。
複製代碼
os_profile {computer_name = "${local.prefix}-${count.index}-vm"admin_username = var.node-definition.admin-usernameadmin_password = var.node-definition.admin-password}
osprofilewindows_config {provisionvmagent = true}
## 加入Rancher
節點配置完成以後,自定義腳本擴展將運行Windows節點命令。
>注意:
>
>這是與Terraform文檔中不一樣類型的自定義腳本擴展,適用於Linux虛擬機。Azure能夠容許你對Windows節點嘗試使用Terraform類型的擴展,但它最終會失敗。
## 耐心一點噢
整個進程須要花費一些時間,須要耐心等待。當Terraform完成以後,將會有一些項目依舊在配置。即便在Kubernetes集羣已經啓動以後,Windows節點將至少須要10分鐘來徹底初始化。正常工做的Windows節點看起來相似於下面的終端輸出:
複製代碼
C:Usersiamsuperman>docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES832ef7adaeca rancher/rke-tools:v0.1.50 "pwsh -NoLogo -NonIn…" 10 minutes ago Up 9 minutes nginx-proxy7e75dffce642 rancher/hyperkube:v1.15.4-rancher1 "pwsh -NoLogo -NonIn…" 10 minutes ago Up 10 minutes kubelete22b656e22e0 rancher/hyperkube:v1.15.4-rancher1 "pwsh -NoLogo -NonIn…" 10 minutes ago Up 9 minutes kube-proxy5a2a773f85ed rancher/rke-tools:v0.1.50 "pwsh -NoLogo -NonIn…" 17 minutes ago Up 17 minutes service-sidekick603bf5a4f2bd rancher/rancher-agent:v2.3.0 "pwsh -NoLogo -NonIn…" 24 minutes ago Up 24 minutes gifted_poincare
Terraform將爲新平臺輸出憑據。
複製代碼
Outputs:
lets-encrypt-email = jason@vanbrackel.netlets-encrypt-environment = productionrancher-admin-password = {REDACTED}rancher-domain-name = https://jvb-win-hybrid.eastus2.cloudapp.azure.com/windows-admin-password = {REDACTED}
# Part3:使用Windows工做負載
## 經過OS定位工做負載
由於Windows容器鏡像和Linux容器鏡像並不相同,咱們須要使用Kubernetes節點的關聯性來肯定咱們的部署目標。每一個節點都有OS標籤以幫助實現這一目的。
複製代碼
kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-0-vm Ready controlplane 16m v1.15.4
etcd-0-vm Ready etcd 16m v1.15.4
win-0-vm Ready worker 5m52s v1.15.4
worker-0-vm Ready worker 12m v1.15.4kubectl describe node worker-0-vm
Name: worker-0-vm
Roles: worker
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=worker-0-vm
kubernetes.io/os=linux
node-role.kubernetes.io/worker=true
...kubectl describe node win-0-vm
Name: win-0-vm
Roles: worker
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=windows
kubernetes.io/arch=amd64
kubernetes.io/hostname=win-0-vm
kubernetes.io/os=windows
`
由Rancher 2.3部署的集羣會自動使用NoSchedule污染Linux worker節點,這意味着工做負載將始終流向Windows節點,除非特別調度了Linux節點而且配置爲可容忍污染。
根據計劃使用集羣的方式,您可能會發現,設置相似的Windows或Linux默認首選項能夠在啓動工做負載時減小開銷。
歡迎添加小助手(wx:rancher2),進官方技術羣,瞭解更多Kubernetes使用攻略