零基礎(chǔ)教程!一文教你使用Rancher 2.3和Terraform運行Windows容器

本文來自Rancher Labs

介 紹

在Kubernetes 1.14版本中已經(jīng)GA了對Windows的支持。這一結(jié)果凝結(jié)了一群優(yōu)秀的工程師的努力,他們來自微軟、Pivotal、VMware、紅帽以及現(xiàn)在已經(jīng)關(guān)閉的Apprenda等幾家公司。我在Apprenda工作時,不定時會為sig-windows社區(qū)做出一些貢獻。即便現(xiàn)在在Rancher Labs任職,也一直關(guān)注它的動向。所以當(dāng)公司決定在Rancher中增加對Windows支持時,我極為興奮。

Rancher 2.3已于本月月初發(fā)布,這是首個GA支持Windows容器的Kubernetes管理平臺。它極大降低了企業(yè)使用Windows容器的復(fù)雜性,并為基于Windows遺留應(yīng)用程序的現(xiàn)代化提供快捷的途徑——無論這些程序是在本地運行還是在多云環(huán)境中運行。此外,Rancher 2.3還可以將它們?nèi)萜骰⑵滢D(zhuǎn)換為高效、安全和可遷移的多云應(yīng)用程序,從而省去重寫應(yīng)用程序的工作。

在本文中,我們將在運行RKE的Kubernetes集群之上配置Rancher集群。我們也將會配置同時支持Linux和Windows容器的集群。完成配置后,我們將聊聊操作系統(tǒng)的定位,因為Kubernetes scheduler需要指導(dǎo)各種Linux和Windows容器在啟動時的部署位置。

我們的目標(biāo)是以完全自動化的方式執(zhí)行這一操作。由于Rancher 2.3目前尚未stable,因此這無法在生產(chǎn)環(huán)境中使用,但如果你正需要使用Azure和Rancher來完成基礎(chǔ)架構(gòu)自動化,那么這對你們的團隊而言將會是一個良好的開端。退一萬步而言,即使你不使用Azure,在本例中的許多概念和代碼都可以應(yīng)用于其他環(huán)境中。

考慮因素

Windows vs. Linux

在我們正式開始之前,我需要告知你許多注意事項和“陷阱”。首先,最顯而易見的就是:Windows不是Linux。Windows新增了支持網(wǎng)絡(luò)網(wǎng)格中的容器化應(yīng)用程序所需的子系統(tǒng),它們是Windows操作系統(tǒng)專有的,由Windows主機網(wǎng)絡(luò)服務(wù)和Windows主機計算服務(wù)實現(xiàn)。操作系統(tǒng)以及底層容器運行時的配置、故障排除以及運維維護將會有顯著區(qū)別。而且,Windows節(jié)點收到Windows Server licensing的約束,容器鏡像也受Windows容器的補充許可條款的約束。

Windows OS版本

WindowsOS版本需要綁定到特定的容器鏡像版本,這是Windows獨有的。使用Hyper-V隔離可以克服這一問題,但是從Kubernetes 1.16開始,Kubernetes不支持Hyper-V隔離。因此,K8S 和 Rancher 僅支持 Windows Server Core 1809 或 Windows Server 2019 (Builds 17763) 及其以上的 Windows 服務(wù)器 (運行 Docker EE-basic 18.09)。

持久性支持和CSI插件

Kubernetes 1.16版本以來,CSI插件支持alpha版本。Windows節(jié)點支持大量的in-tree和flex volume。

CNI插件

Rancher 支持僅限于flannel提供的主機網(wǎng)關(guān)(L2Bridge)和VXLAN(Overlay)網(wǎng)絡(luò)支持。在我們的方案中,我們將利用默認的VXLAN,因為當(dāng)節(jié)點并不都在同一個網(wǎng)絡(luò)上時,主機網(wǎng)關(guān)選項需要User Defined Routes配置。這取決于提供商,所以我們將利用VXLAN功能的簡單性。根據(jù)Kubernetes文檔,這是alpha級別的支持。當(dāng)前沒有支持Kubernetes網(wǎng)絡(luò)策略API的開源Windows網(wǎng)絡(luò)插件。

其他限制

請確保你已經(jīng)閱讀了Kubernetes文檔,因為在Windows容器中有許多功能無法實現(xiàn),或者其功能和Linux中的相同功能實現(xiàn)方式有所不同。

Kubernetes文檔:

https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/#limitations

基礎(chǔ)架構(gòu)即代碼

自動化是實現(xiàn)DevOps的第一種方式。我們將自動化我們的Rancher集群和要在該集群中配置的Azure節(jié)點的基礎(chǔ)架構(gòu)。

Terraform

Terraform是一個開源的基礎(chǔ)架構(gòu)自動化編排工具,它幾乎支持所有市面上能見到的云服務(wù)提供商。今天我們將使用這一工具來自動化配置。確保你運行的Terraform版本至少是Terraform 12。在本文中,使用Terraform 版本是v0.12.9。

$ terraform version
Terraform v0.12.9

RKE Provider

用于Terraform 的RKE provider是一個社區(qū)項目,并非由Rancher官方進行研發(fā)的,但包括我在內(nèi)的Rancher的很多工程師都在使用。因為這是一個社區(qū)provider而不是Terraform官方的provider,因此你需要安裝最新版本到你的Terraform插件目錄中。對于大部分的Linux發(fā)行版來說,你可以使用本文資源庫中包含的setup-rke-terraform-provider.sh腳本。

Rancher Provider

用于Terraform的Rancher2 provider是Terraform支持的provider,它通過Rancher REST API來自動化Rancher。我們將用它從Terraform的虛擬機中創(chuàng)建Kubernetes集群,這一虛擬機需要使用Azure Resource Manager和Azure Active Directory Terraform Provider進行創(chuàng)建。

本例的Format

本文中的Terraform模型的每個步驟都會被拆分成子模型,這將增強模型可靠性并且將來如果你創(chuàng)建了其他自動化架構(gòu),這些模型都可以重新使用。

Part1:設(shè)置Rancher集群

登錄到Azure

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"
    }
  }
]

設(shè)置Resource Group

Azure Resource Group是Rancher集群的節(jié)點和其他虛擬硬件存儲的位置范圍。我們實際上將會創(chuàng)建兩個組,一個用于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
}

設(shè)置硬件

虛擬網(wǎng)絡(luò)

我們將需要一個虛擬網(wǎng)絡(luò)和子網(wǎng)。我們將使用network-module在各自的資源組中分別設(shè)置它們。

我們將使用node-module設(shè)置每個節(jié)點。既然每個節(jié)點都需要安裝Docker,那么我們在使用Rancher install-docker腳本配置和安裝Docker時,我們需要運行cloud-init文件。這個腳本將檢測Linux發(fā)行版并且安裝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:
- [ sh, -c, "curl https://releases.rancher.com/install-docker/{docker-version}.sh | sh && sudo usermod -a -G docker{admin-username}" ]
- [ sh, -c, "${additionalCommand}"]


模板中的附加命令塊用這些節(jié)點的sleep 0填充,但是稍后該命令將用于Linux節(jié)點,以將Rancher管理的自定義集群節(jié)點加入平臺。



**設(shè)置節(jié)點**



接下來,我們將為每個角色創(chuàng)建幾組節(jié)點:控制平面、etcd和worker。我們需要考慮幾件事,因為Azure處理其虛擬網(wǎng)絡(luò)的方式有一些獨特之處。它會保留前幾個IP供自己使用,因此在創(chuàng)建靜態(tài)IP時需要考慮這一特性。這就是在NIC創(chuàng)建中的4個IP,由于我們也管理子網(wǎng)的IP,因此我們在每個IP中都進行了處理。

resource "azurerm_network_interface" "nic" {
count = var.node-count
name = "{local.prefix}-{count.index}-nic"
location = var.resource-group.location
resource_group_name = var.resource-group.name

ip_configuration {
name = "{local.prefix}-ip-config-{count.index}"
subnet_id = var.subnet-id
private_ip_address_allocation = "static"
private_ip_address = cidrhost("10.0.1.0/24", count.index + var.address-starting-index + 4)
public_ip_address_id = azurerm_public_ip.publicIp[count.index].id
}
}


## 為什么不對私有IP使用動態(tài)分配?



在創(chuàng)建并完全配置節(jié)點之前,Azure的Terraform provider將無法獲取IP地址。而通過靜態(tài)處理,我們可以在生成RKE集群期間使用地址。當(dāng)然,還有其他方法也能解決這一問題,如將基礎(chǔ)架構(gòu)配置分成多個來運行。但是為簡單起見,還是對IP地址進行靜態(tài)管理。



**設(shè)置前端負載均衡器**



默認情況下,Rancher安裝程序?qū)诿總€worker節(jié)點安裝一個ingress controller,這意味著我們應(yīng)該在可用的worker節(jié)點之間負載均衡任何流量。我們也將會利用Azure的功能來為公共IP創(chuàng)建一個公共的DNS入口,并且將其用于集群。這可以在`loadbalancer-module`中完成。



https://github.com/JasonvanBrackel/cattle-drive/tree/master/terraform-module/loadbalancer-module

resource "azurerm_public_ip" "frontendloadbalancer_publicip" {
name = "rke-lb-publicip"
location = var.resource-group.location
resource_group_name = var.resource-group.name
allocation_method = "Static"
domain_name_label = replace(var.domain-name-label, ".", "-")
}


作為替代方案,其中包含使用cloudflare DNS的代碼。我們在這篇文章中沒有使用這一方案,但是你可以不妨一試。如果你使用這個方法,你將需要重置DNS緩存或主機文件入口,以便你的本地計算機可以調(diào)用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 suffixes
status = "active"
paused = false
}
}

Add a record to the domain

resource "cloudflare_record" "domain" {
zone_id = data.cloudflare_zones.zones.zones[0].id
name = var.domain-name
value = var.ip-address
type = "A"
ttl = "120"
proxied = "false"
}


**使用RKE安裝Kubernetes**



我們將使用Azure和Terraform的動態(tài)代碼塊創(chuàng)建的節(jié)點與開源RKE Terraform Provider來創(chuàng)建一個RKE集群。


dynamic nodes {
for_each = module.rancher-control.nodes
content {
address = module.rancher-control.publicIps[nodes.key].ip_address
internal_address = module.rancher-control.privateIps[nodes.key].private_ip_address
user = module.rancher-control.node-definition.admin-username
role = ["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/

  addons = <<EOL
---
kind: ServiceAccount
apiVersion: v1
metadata:
  name: tiller
  namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: tiller
  namespace: kube-system
subjects:
- kind: ServiceAccount
  name: tiller
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
EOL
}

初始化Helm

Terraform可以運行本地腳本。既然我們將要使用Helm來安裝cert-manager和Rancher,我們需要初始化Helm。

安裝cert-manager

這一步和Rancher文檔中【使用Tiller安裝cert-manager】的內(nèi)容一樣。

https://rancher.com/docs/rancher/v2.x/en/installation/ha/helm-rancher/#let-s-encrypt

resource "null_resource" "install-cert-manager" {
  depends_on = [null_resource.initialize-helm]
  provisioner "local-exec" {
    command = file("../install-cert-manager.sh")
  }
}

安裝Rancher

這一步和官方文檔中【安裝Rancher】的內(nèi)容一樣。

https://rancher.com/docs/rancher/v2.x/en/installation/ha/helm-rancher/

install-rancher腳本有很多個版本,我們所使用的版本要求要有Let’s Encrypt的證書。如果你更習(xí)慣使用自簽名的證書,你需要將install-rancher.sh的symlink更改為指向其他版本,并從下面的示例代碼中刪除let-encrypt變量。

resource "null_resource" "install-rancher" {
  depends_on = [null_resource.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引導(dǎo)程序

Terraform的Rancher2 Provider包含了一個引導(dǎo)模式。這允許我們可以設(shè)置一個admin密碼。你可以在rancherbootstrap-module中看到這一步。

provider "rancher2"  {
  alias = "bootstrap"

  api_url   = var.rancher-url
  bootstrap = true

  insecure = true
}

resource "rancher2_bootstrap" "admin" {
  provider = rancher2.bootstrap
  password = var.admin-password
  telemetry = true
}

我們在這里設(shè)置集群url。

provider "rancher2" {
  alias = "admin"

  api_url = rancher2_bootstrap.admin.url
  token_key = rancher2_bootstrap.admin.token

  insecure = true
}


resource "rancher2_setting" "url" {
  provider = rancher2.admin
  name = "server-url"
  value = var.rancher-url
}

Part2:設(shè)置Rancher管理的Kubernetes集群

為Azure創(chuàng)建服務(wù)主體

在我們可以使用Azure cloud來創(chuàng)建Load Balancer 服務(wù)和Azure存儲之前,我們需要先為Cloud Controller Manager配置connector。因此,我們在cluster-module和serviceprincipal-module中創(chuàng)建了一個服務(wù)主體,其作用域為集群的Resource Group。

resource "azuread_application" "ad-application" {
  name                       = var.application-name
  homepage                   = "https://${var.application-name}"
  identifier_uris            = ["http://${var.application-name}"]
  available_to_other_tenants = false
}

resource "azuread_service_principal" "service-principal" {
  application_id                = azuread_application.ad-application.application_id
  app_role_assignment_required  = true
}

resource "azurerm_role_assignment" "serviceprincipal-role" {
  scope                = var.resource-group-id
  role_definition_name = "Contributor"
  principal_id         = azuread_service_principal.service-principal.id
}

resource "random_string" "random" {
  length = 32
  special = true
}

resource "azuread_service_principal_password" "service-principal-password" {
  service_principal_id = azuread_service_principal.service-principal.id
  value                = random_string.random.result
  end_date             = timeadd(timestamp(), "720h")
}

定義自定義集群

我們需要設(shè)置flannel 網(wǎng)絡(luò)選項以支持Windows flannel驅(qū)動。你將會注意到Azure provider的配置。

resource "rancher2_cluster" "manager" {
  name = var.cluster-name
  description = "Hybrid cluster with Windows and Linux workloads"
  # windows_prefered_cluster = true Not currently supported
  rke_config {
    network {
      plugin = "flannel"
      options = {
        flannel_backend_port = 4789
        flannel_backend_type = "vxlan"
        flannel_backend_vni = 4096
      }
    }
    cloud_provider {
      azure_cloud_provider {
        aad_client_id = var.service-principal.client-id
        aad_client_secret = var.service-principal.client-secret
        subscription_id = var.service-principal.subscription-id
        tenant_id = var.service-principal.tenant-id
      }
    }
  }
}

創(chuàng)建虛擬機

這些虛擬機的創(chuàng)建過程與早期計算機相同,并且包含Docker安裝腳本。這里唯一的改變是使用來自之前創(chuàng)建集群的linux節(jié)點命令的附加命令。

module "k8s-worker" {
  source = "./node-module"
  prefix = "worker"

  resource-group = module.k8s-resource-group.resource-group
  node-count = var.k8s-worker-node-count
  subnet-id = module.k8s-network.subnet-id
  address-starting-index = var.k8s-etcd-node-count + var.k8s-controlplane-node-count
  node-definition = local.node-definition
  commandToExecute = "${module.cluster-module.linux-node-command} --worker"
}

創(chuàng)建Windows Workers

Windows worker進程類似于Linux進程,但有一些例外。由于Windows不支持cloud-init文件,我們需要創(chuàng)建一個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-username
  admin_password = var.node-definition.admin-password
}

os_profile_windows_config {
  provision_vm_agent = true
}

加入Rancher

節(jié)點配置完成之后,自定義腳本擴展將運行Windows節(jié)點命令。

注意:

這是與Terraform文檔中不同類型的自定義腳本擴展,適用于Linux虛擬機。Azure可以允許你對Windows節(jié)點嘗試使用Terraform類型的擴展,但它最終會失敗。

耐心一點噢

整個進程需要花費一些時間,需要耐心等待。當(dāng)Terraform完成之后,將會有一些項目依舊在配置。即使在Kubernetes集群已經(jīng)啟動之后,Windows節(jié)點將至少需要10分鐘來完全初始化。正常工作的Windows節(jié)點看起來類似于下面的終端輸出:

C:\Users\iamsuperman>docker ps
CONTAINER ID        IMAGE                                COMMAND                  CREATED             STATUS              PORTS               NAMES
832ef7adaeca        rancher/rke-tools:v0.1.50            "pwsh -NoLogo -NonIn…"   10 minutes ago      Up 9 minutes                            nginx-proxy
7e75dffce642        rancher/hyperkube:v1.15.4-rancher1   "pwsh -NoLogo -NonIn…"   10 minutes ago      Up 10 minutes                           kubelet
e22b656e22e0        rancher/hyperkube:v1.15.4-rancher1   "pwsh -NoLogo -NonIn…"   10 minutes ago      Up 9 minutes                            kube-proxy
5a2a773f85ed        rancher/rke-tools:v0.1.50            "pwsh -NoLogo -NonIn…"   17 minutes ago      Up 17 minutes                           service-sidekick
603bf5a4f2bd        rancher/rancher-agent:v2.3.0         "pwsh -NoLogo -NonIn…"   24 minutes ago      Up 24 minutes                           gifted_poincare

Terraform將為新平臺輸出憑據(jù)。

Outputs:

lets-encrypt-email = jason@vanbrackel.net
lets-encrypt-environment = production
rancher-admin-password = {REDACTED}
rancher-domain-name = https://jvb-win-hybrid.eastus2.cloudapp.azure.com/
windows-admin-password = {REDACTED}

Part3:使用Windows工作負載

通過OS定位工作負載

因為Windows容器鏡像和Linux容器鏡像并不相同,我們需要使用Kubernetes節(jié)點的關(guān)聯(lián)性來確定我們的部署目標(biāo)。每個節(jié)點都有OS標(biāo)簽以幫助實現(xiàn)這一目的。

> 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.4
> kubectl 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節(jié)點,這意味著工作負載將始終流向Windows節(jié)點,除非特別調(diào)度了Linux節(jié)點并且配置為可容忍污染。

根據(jù)計劃使用集群的方式,您可能會發(fā)現(xiàn),設(shè)置類似的Windows或Linux默認首選項可以在啟動工作負載時減少開銷。

歡迎添加小助手(wx:rancher2),進官方技術(shù)群,了解更多Kubernetes使用攻略

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容