Ansible for k8s-深蓝源码网
导读 用ansible来创建k8s,这类项目已经很多了,在github上面随意可以搜到很多,而这篇文章主要介绍的是如果用ansible来做日常的k8s运维和开发部署。本文中的例子可以在https://github.com/u2takey/ansible-k8s找到helm和kustomize的问题从我第一次使用helm就觉得这个东西的设计实……
用 ansible 来创建 k8s,这类项目已经很多了,在 github 上面随意可以搜到很多,而这篇文章主要介绍的是如果用 ansible 来做日常的 k8s 运维和开发部署。
本文中的例子可以在 https://github.com/u2takey/ansible-k8s 找到
helm 和 kustomize 的问题
从我第一次使用 helm 就觉得这个东西的设计实在古怪:
- 一个包(配置)管理工具依赖服务端(tiller)
- 做的事情很简单,设计却过于复杂(看看 helm 有多少命令和参数就知道了)
- template 可读性很差,表达能力却很弱(受制于go-template的表达能力)
- 99% 的用户不会安装 tiller, 只是拿来做 template 渲染工具,但是就算作为一个简单的渲染工具,helm也不好用
- 其他缺陷:参考
后来出现了 kustomize,kustomize的设计并不依赖服务端,而是想做好本地渲染,然而几次使用之后发现,kustomize 显然还是失败了
- kustomize 的设计有点像 ansible了,然而表达能力还是很差,设计却过于复杂
- 作为了一个 yaml 工具,kustomize 带了太多k8s属性,比如 kustomize 了解什么是 images,什么是 configmap,这个设计显然不够灵活
- 如果 kustomize (很有希望的)像ansible好好学习,能做好一个专用领域的 ansible 工具,易用性能肯定能好很多
求助于 ansible
关于运维和部署,ansible已经积累了太多经验,虽然本质上 ansible 最初的设计还是针对 "hosts", 并不是针对集群,ansible的 k8s module 质量也参差不齐,但是尽管如此,使用时候你会发现,ansible 在运维 k8s 的能力上还是很强。
用 ansible 部署 k8s 集群
这部分不是本文的重点,ansible 部署 k8s 是比较常见的 k8s 部署方式,这里给几个 star 比较高的项目,不再细述。
用 ansible 运维 k8s 服务
ansible 主要可以使用 k8s 模块来管理 k8s 资源
比如创建一个 namespace,可以使用下面的写法
- name: Create a k8s namespace k8s: name: testing api_version: v1 kind: Namespace state: present
创建 service 的写法
- 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
上面的这种 inline 的写法实际上可读性比较差,更推荐使用 src(读取文件) 或者 definition + lookup + template 语句的办法来创建资源,ansible 的 template 使用 jinja2 来渲染,表达能力很强。
- name: Create a Deployment by reading the definition from a local file k8s: state: present src: /testing/deployment.yml - name: Read definition file from the Ansible controller file system after Jinja templating k8s: state: present definition: "{{ lookup('template', '/testing/deployment.yml.j2') }}"
一个完整的例子
下面我们看一个完整的例子,这个例子里面我们有两个集群,分别叫 4lr4c3wx 和 8keawqnz, 并且我们在本地的 admin.conf 里面加入了这两个 context, 所以我们不用在 ansible config里面添加相关密钥信息。
- 使用
ansible-galaxy初始化 role
➜ ansible-galaxy role init nginx ➜ ll nginx .rw-r--r-- 1.3k leiwang 4 Jan 15:11 README.md drwxr-xr-x - leiwang 4 Jan 15:11 defaults drwxr-xr-x - leiwang 4 Jan 15:11 files drwxr-xr-x - leiwang 4 Jan 15:11 handlers drwxr-xr-x - leiwang 4 Jan 15:11 meta drwxr-xr-x - leiwang 4 Jan 15:11 tasks drwxr-xr-x - leiwang 4 Jan 15:13 templates drwxr-xr-x - leiwang 4 Jan 15:11 tests drwxr-xr-x - leiwang 4 Jan 15:11 vars
- 修改 host 和 ansible.cfg, 指向两个集群.
# ansible.cfg [defaults] inventory = hosts.ini host_key_checking = False pipelining = True gathering = smart fact_caching = jsonfile fact_caching_timeout = 86400 fact_caching_connection = /tmp/ansible_fact_cache forks = 20 # host [test] 4lr4c3wx context=4lr4c3wx 8keawqnz context=8keawqnz [test:vars] ansible_connection=local ansible_python_interpreter=~/miniconda3/bin/python
- 修改 task/main.yml, 这里我们编写两个任务,一是操作 namespace, 二是创建 nginx deployment 和 service,支持 namespace 和 state 参数,支持 state也就是说 支持创建或者删除,对 namespace的操作加上
ignore_errors, 因为创建或者删除 namespace 时可能会报错,我们希望忽略这种错误。
--- - debug: var=context - name: set namespace {{ namespace }} to {{ state }} k8s: context: "{{ context }}" api_version: v1 kind: Namespace name: "{{ namespace }}" state: "{{ state }}" ignore_errors: true - name: set nginx deployment to {{ state }} k8s: context: "{{ context }}" state: "{{ state }}" definition: "{{ lookup('template', 'nginx.yml.j2') | from_yaml_all | list }}" namespace: "{{ namespace }}"
- nginx.yml.j2 里nginx deployment和service,实际上这两个 object 分开会更好,这里放在一起只是为了演示,如果放在一起应该用
from_yaml_all+listfilter来处理
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx namespace: {{ namespace }} labels: version: v2 spec: # 略 --- apiVersion: v1 kind: Service metadata: name: nginx namespace: {{ namespace }} spec: # 略
- playbook include 刚刚编写的 nginx role
--- - name: example k8s playbook hosts: test vars: namespace: default roles: - nginx
- 运行 playbook
➜ ansible-playbook main.yml PLAY [example k8s playbook] ********************************************************************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************************************************************************** ok: [test_cluster_2] ok: [test_cluster_1] TASK [nginx : debug] **************************************************************************************************************************************************************** ok: [test_cluster_1] => { "context": "4lr4c3wx" } ok: [test_cluster_2] => { "context": "8keawqnz" } TASK [nginx : set namespace default to present] ************************************************************************************************************************************* ok: [test_cluster_1] ok: [test_cluster_2] TASK [nginx : set nginx deployment to present] ************************************************************************************************************************************** changed: [test_cluster_1] changed: [test_cluster_2] PLAY RECAP ******************************
