使用 Ansible 管理 Kubernetes 資源

前兩天,一篇「Think twice before using Helm[1]」(譯文:「恕我直言,對Helm你們仍是要三思然後用」) 引發了你們的關注。做者從認證,生命週期管理,錯誤處理等多個角度說明了 Helm 自身的問題。我基本贊同做者的觀點。多數狀況下咱們只是把 helm 當作一個模板引擎在使用,把 charts 生成 Kubernetes 能夠處理的格式。可是從使用角度來講,這個模板實現的過重了。有興趣的能夠去讀讀原文。html

那若是 Helm 不輕量好用的話,咱們有啥其餘選擇?python

Ansible 作爲部署管理的工具,正在受到愈來愈多的運維人員的追捧。他支持 Jinja2 的模板引擎,並且是無代理節點的架構,很方便來作一些模板工做。因此本文來介紹使用 Ansible 如何管理 Kubernetes 上面的資源。web

首先使用 Ansible 避免不了使用其模塊。與 Kubernetes 相關的模塊能夠從[2]找到。如今主要有k8s, k8s_facts, k8s_scale, kubernetes和oc 5個模塊。其中 kubernetes 和 oc 模塊由於實現邏輯很差用,在 ansible 2.6 版本中已經廢棄掉, 推薦使用前三個。其中,k8s_scale 來自 ansible 2.5, k8s 來自 ansible 2.6, k8s_facts 來自 ansible 2.7。使用這三個模塊的話,還須要安裝 openshift 的 Python 包。如下代碼所有基於 ansible 2.7 版本。api

1、k8s 模塊

管理 kubernetes 各類資源的話,使用 k8s 模塊就能夠了,以下是建立 namespace 的寫法架構

  • name: Create a k8s namespace
    k8s:
    name: testing
    api_version: v1
    kind: Namespace
    state: present
    若是要建立一個 Service, 也可使用以下面的寫法。app

  • name: Create a Service object from an inline definition
    k8s:
    state: present
    definition:
    apiVersion: v1
    kind: Service
    metadata:
    name: web
    namespace: testing
    labels:
    app: galaxy
    service: web
    spec:
    selector:
    app: galaxy
    service: web
    ports:
    • protocol: TCP
      targetPort: 8000
      name: port-8000-tcp
      port: 8000
      能夠看到 definition 裏面就是原生的 Kubernetes 裏面的寫法,而 k8s 模塊的參數也寫少,因此上手會很快。

若是 k8s 模塊和 ansible lookup 插件合用的話,能夠寫出更加簡潔的代碼,以下運維

#tasks.ymltcp

  • name: Create a Service object from an external file
    var:
    name: "web"
    k8s:
    state: present
    definition:
    {{ lookup('template', '/path/to/service.yml') | to_yaml(indent=6) }}
    #/path/to/service.yml

    apiVersion: v1
    kind: Service
    metadata:
    name: {{ name }} # <-- 這裏可使用變量
    namespace: testing
    labels:
    app: galaxy
    service: web
    spec:
    selector:
    app: galaxy
    service: web
    ports:ide

    • protocol: TCP
      targetPort: 8000
      name: port-8000-tcp
      port: 8000
      能夠看到 Kubernetes service 文件能夠徹底從 task 裏面獨立出來,獨立後的寫法就是原生的 kubernetes 的格式,基本就和 Charts 的結構差很少了。

基於此,徹底可使用這種方式替換掉 helm 的模板功能,並且沒有引入任何額外的依賴,就是直接的 ansible 生成相關文件,丟給 kubernetes api 來處理。等部署完成後,咱們也能夠脫離 Ansible 繼續經過 kubelet 命令維護這些資源。也正是因爲這麼簡潔的實現,k8s 模塊能夠管理 Kubernetes 和 OpenShift, 也能夠管理各類 CRD 資源。工具

相比於 helm , 這種方法的缺點在於 YAML 文件都要本身寫,沒有社區在維護的 Charts。不像 helm 那樣,一個命令就能夠把服務都安裝上。前期的工做仍是挺多的。可是從另一個角度來講,社區維護的 Charts 作一些 Demo 還能夠,真要生產上面使用,仍是要作大量工做的。因此從這個角度上講,使用 Ansible 也沒有帶來太大的工做量。

我更期待社區可使用 Ansible 直接管理 Charts 資源,或能夠有一個工具把 Charts 的 Go 模板轉成 Ansible 能夠接受的 Jinja2 格式。

2、k8s_scale 和 k8s_facts 模塊

這兩個模塊算輔助的功能,我以爲使用的機會可能並不會太多。k8s_scale 的例子以下:

  • name: Scale deployment up, and extend timeout
    k8s_scale:
    api_version: v1
    kind: Deployment
    name: elastic
    namespace: myproject
    replicas: 3
    wait_timeout: 60

  • name: Scale deployment down when current replicas match
    k8s_scale:
    api_version: v1
    kind: Deployment
    name: elastic
    namespace: myproject
    current_replicas: 3
    replicas: 2
    它能夠動態調整 Deployment 的 replicas 個數,基本上等同於kubectl scale 命令,可是這個功能基本可使用 k8s 模塊經過改變 replicas 參數來調整。

k8s_facts的例子以下:

  • name: Get an existing Service object
    k8s_facts:
    api_version: v1
    kind: Service
    name: web
    namespace: testing
    register: web_service
    使用他,你能夠檢查某個資源是否存在,若是存在的話,還能夠得到這個資源的yaml 文件描述,我以爲在 Ansible 流程控制中會有一些做用,能夠根據當前 Kubernets 裏面資源狀況,有選擇的作一些動做。

3、小技巧

由於 Ansible 是 Python 編寫的,在使用 pip 安裝時容易破壞系統已經安裝的 Python 包,推薦使用虛擬環境來安裝。

#mkvirtualenv --system-site-packages ansible
#pip install 'ansible<2.7' openshift

使用時,須要指定 Ansible 使用的 python interpreter 變量

#workon ansible
#ansible-playbook -i localhost, -c local test.yml -e ansible_python_interpreter=${VIRTUAL_ENV}/bin/python

4、demo

如下是使用 ansible 在 OpenShift 上面部署 echoserver 的一個完整例子


  • hosts: localhost
    connection: local
    gather_facts: false
    vars:
    namespace: demo
    tasks:
    • name: Create echo server deployment config
      k8s:
      namespace: "{{ namespace }}"
      definition:
      apiVersion: v1
      kind: DeploymentConfig
      metadata:
      name: echoserver
      spec:
      replicas: 1
      template:
      metadata:
      labels:
      app: echoserver
      spec:
      containers:
      • name: echoserver
        image: googlecontainer/echoserver:1.5
        readnessProbe:
        httpGet:
        port: 8080
        path: /
        initialDelaySeconds: 20
        periodSeconds: 5
        livenessProbe:
        httpGet:
        port: 8080
        path: /
        initialDelaySeconds: 10
        periodSeconds: 3
    • name: Create echo server service
      k8s:
      namespace: "{{ namespace }}"
      definition:
      apiVersion: v1
      kind: Service
      metadata:
      name: echoserver
      spec:
      ports:
      • name: http
        port: 8080
        targetPort: 8080
        selector:
        app: echoserver
    • name: Create echo server router
      k8s:
      namespace: "{{ namespace }}"
      definition:
      kind: Route
      apiVersion: route.openshift.io/v1
      metadata:
      name: echoserver
      spec:
      host: echoserver.local
      to:
      kind: Service
      name: echoserver
      port:
      targetPort: http

參考文獻:

[1]https://medium.com/virtuslab/think-twice-before-using-helm-25fbb18bc822
[2]https://docs.ansible.com/ansible/latest/modules/list_of_clustering_modules.html

相關文章
相關標籤/搜索