文章目录
Ansible的Kubernetes模块
截止到目前,Ansible 2.9内置了以下模块用来对OpenShift和Kubernetes操作。
- k8s – Manage Kubernetes (K8s) objects
- k8s_auth – 登录认证模块
- k8s_info – 描述Kubernetes的对象
- k8s_scale – 扩展Deployment, ReplicaSet, ReplicationController或Job的数量
- k8s_service – 管理Kubernetes的服务
Ansible访问OpenShift或Kubernetes的过程
Ansible是通过基于python的k8s模块(曾经是openshift_raw)访问OpenShift或Kubernetes服务器的。它采用REST的方式访问集群,因此不需要本地运行OpenShift或Kubernetes客户端。
不过如果运行Ansible的环境也有oc客户端,并且oc客户端已经登录集群了,那么Ansible模块可以共享这个登录会话连接,可以在Playbook中直接对Kubernetes进行操作即可。如果oc客户端未登录OpenShift集群,那么Ansible模块可直接登录OpenShift或Kubernetes,然后再能进行其它操作。
安装环境
编辑Ansible Playbook工具
为了编辑Ansible的Playbook文件,可以使用VSCode的Ansible插件,另外还可配合vscode-ssh插件远程编辑Playbook文件。Ansible插件可以提示模块和参数。
安装oc客户端
$ wget https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.5.5/openshift-client-linux-4.5.5.tar.gz
$ tar -xzf openshift-client-linux-4.5.5.tar.gz -C /usr/bin/
安装Ansible
- 操作系统可以是RHEL 7/8、CentOS 7/8。用root用户依次执行以下命令安装rpm和ansible。
$ yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
$ yum install ansible -y
说明:RHEL 7 使用“epel-release-latest-7.noarch.rpm”、RHEL 8 使用“epel-release-latest-8.noarch.rpm”。
2. 验证Ansible环境,其中Ansible的版本是2.9.11;“config file”是Ansible使用的配置文件;“configured module search path”是Ansible模块的目录;“ansible python module location”是python模块的目录;python使用的版本是3.6.8环境。
$ $ ansible --version
ansible 2.9.11
config file = /home/student1/.ansible.cfg
configured module search path = ['/home/student1/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Dec 5 2019, 15:45:45) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
安装python相关模块
根据Ansible的文档说明,为了能操作Kubernetes或OpenShift,需要安装以下python的模块。
$ pip install pyyaml
$ pip install kubernetes
$ pip install openshift
通过Ansible实现DevOps
从github上获取YAML文件
- 创建内容如下的clone-git.yml文件,将本文用到的yaml文件从github上clone到本地的~/ansible目录。
- hosts: localhost
gather_facts: no
tasks:
- name: Checkout The Code From Github Using Ansible.
git:
repo: 'https://github.com/liuxiaoyu-git/ansible-kubernetes.git'
dest: ~/ansible
register: clone
- 执行命令
$ ansible-playbook clone-git.yml
PLAY [localhost] ***********************************************************************************************************************************
TASK [Checkout The Code From Github Using Ansible.] ***********************************************************************************************************************************
changed: [localhost]
PLAY RECAP ***********************************************************************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 查看通过ansible下载的文件。
$ ll ~/ansible
total 24
-rw-rw-r--. 1 student1 student1 632 Aug 20 14:50 del-pod.yml
-rw-rw-r--. 1 student1 student1 465 Aug 20 14:50 hello-deployment.yml
-rw-rw-r--. 1 student1 student1 572 Aug 20 14:50 hello-openshift.yml
-rw-rw-r--. 1 student1 student1 415 Aug 20 14:50 pod-list.yml
-rw-rw-r--. 1 student1 student1 474 Aug 20 14:33 testing-login.yml
-rw-rw-r--. 1 student1 student1 178 Aug 20 14:33 testing-nologin.yml
创建NameSpace
- 查看testing-nologin.yml文件。本Playbook是在OpenShift中创建名为testing的项目。
说明:在hosts中指定的是localhost,这是由于我们直接是在本机运行ansible-abp脚本,而不是在远程节点上运行ansible-abp脚本。
- hosts: localhost
gather_facts: false
tasks:
- name: Create a k8s namespace
k8s:
name: testing
api_version: v1
kind: Namespace
state: present
- oc客户端连到OpenShift集群。
$ oc login https://<OCP-API-Server>:6443 -u <USERNAME> -p <PASSWORD>
- 运行Ansible playbook,创建testing项目。可以看到Playbook运行结果是“changed=1”。
$ ansible-playbook testing-nologin.yml
PLAY [localhost] ***************************************************************************************************************************
TASK [Create a k8s namespace] **************************************************************************************************************
changed: [localhost]
PLAY RECAP *********************************************************************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 验证,查看testing项目。
$ oc get project testing
NAME DISPLAY NAME STATUS
testing Active
- 删除项目后退出客户端和集群的会话连接。
$ oc delete project testing
$ oc logout
- 再运行playbook,发现会出现错误。从错误提示看,是由于当前客户端没有连到OpenShift集群,所以对集群的操作报“ForbiddenError”。
$ ansible-playbook testing-nologin.yml
PLAY [localhost] ***********************************************************************************************************************************
TASK [Create a k8s namespace] ***********************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: raise ApiException(http_resp=r)
fatal: [localhost]: FAILED! => changed=false
module_stderr: |-
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/openshift/dynamic/discovery.py", line 72, in __init_cache
self._cache = json.load(f, cls=CacheDecoder(self.client))
File "/usr/lib64/python3.6/json/__init__.py", line 299, in load
parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
File "/usr/lib64/python3.6/json/__init__.py", line 367, in loads
return cls(**kw).decode(s)
TypeError: 'CacheDecoder' object is not callable
。。。。
。。。。
openshift.dynamic.exceptions.ForbiddenError: 403
Reason: Forbidden
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'X-Kubernetes-Pf-Flowschema-Uid': '3404ba15-4ff8-485c-bf1b-a2e99429b516', 'X-Kubernetes-Pf-Prioritylevel-Uid': '37685748-0d25-4647-8911-4bc162270ee0', 'Date': 'Wed, 19 Aug 2020 15:24:30 GMT', 'Content-Length': '189'})
HTTP response body: b'{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"forbidden: User \\"system:anonymous\\" cannot get path \\"/apis\\"","reason":"Forbidden","details":{},"code":403}\n
- 刚刚oc客户端退出了和OpenShift集群的连接会话,这种情况下可以在playbook中先建立客户端和集群的连接会话,然后再进行操作。查看testing-login.yml文件,它使用了k8s_auth模块登录OpenShift集群,而host为集群的API-Server登录地址。另外为了简化,登录的usename和password直接用的是明文,建议在生产环境中使用加密方式提供登录密码。
- hosts: localhost
gather_facts: false
tasks:
- name: Try to login to OCP cluster
k8s_auth:
host: https://api.cluster-shang-b982.shang-b982.example.opentlc.com:6443
username: opentlc-mgr
password: r3dh4t1!
validate_certs: no
register: k8s_auth_result
- name: Create a k8s namespace
k8s:
name: testing
api_version: v1
kind: Namespace
state: present
api_key: "{{ k8s_auth_result.k8s_auth.api_key }}"
- 运行新的playbook,确认可以成功运行(changed=1)。
$ ansible-playbook testing-login.yml
PLAY [localhost] **********************************************************************************************************************************
TASK [Try to login to OCP cluster] **********************************************************************************************************************************
ok: [localhost]
TASK [Create a k8s namespace] **********************************************************************************************************************************
changed: [localhost]
PLAY RECAP **********************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 最后,再次用oc客户端登录OpenShift集群,并查看上一步创建的testing项目。
创建登录密码的加密文件
以上我们在testing-login.yml中直接使用了明文的登录密码。为了安全起见可以将密码加密,然后再在Playbook中使用。
- 执行命令创建加密密码的文件。该文件实际相当于一个对称秘钥,它有两个作用,1)用来对需要保护的进密码行加密,2)用来还原已经加密的密码。
$ echo 'mypassword' > decrypt_passwd
- 执行命令创建密码加密文件secrets,所有需要加密的密码放在此文件中。
$ ansible-vault create --vault-id=decrypt_passwd mysecrets
然后在编辑界面中将以下内容加入到文件中。后面在Playbook中 就可以用“ocp_password”访问到OpenShift使用的到密码“r3dh4t1!”。
ocp_password: r3dh4t1!
- 保存后可以查看mysecrets文件内容。
$ more mysecrets
$ANSIBLE_VAULT;1.1;AES256
30663865643634373038313139383537663138313463306534666231313136653139663632663863
3934353961666164326166653762323133386238343266320a666638653639366539303738663938
66386266373331366430363639666133393138633434373930646439303936373865663935663565
3263333033663065390a336332623131383364306337303734616132326130363038656335383366
65636133633038626139636538333437376535353139393562316535336133316338
- 可以用以下命令编辑内容被加密的mysecrets文件。
$ ansible-vault edit --vault-id=decrypt_passwd mysecrets
创建变量文件
以上我们在testing-login.yml中直接使用OpenShift的登录地址,这样如果该地址发生变化,我们不得不修改所有直接使用该地址的Playbook。为此,我们可以将这个地址存放在变量文件中,然后在后面的Playbook中统一引用“ocp_master”变量即可。
- 创建内容如下的myvars文件,其中包括了OpenShift的Master地址和登录OpenShift的用户。
ocp_master: https://api.cluster-shang-b982.shang-b982.example.opentlc.com:6443
ocp_username: opentlc-mgr
创建Deployment资源
- 查看hello-openshift.yml文件,它定义了一个Deployment的Kubernetes对象,其中部署了openshift/hello-openshift容器。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-openshift
labels:
name: hello-openshift
spec:
selector:
matchLabels:
app: hello-openshift
replicas: 1
template:
metadata:
labels:
app: hello-openshift
spec:
containers:
- name: hello-openshift
image: openshift/hello-openshift
ports:
- containerPort: 8080
protocol: TCP
resources:
requests:
cpu: 300m
memory: 64Mi
limits:
cpu: 600m
memory: 128Mi
- 查看hello-deployment.yml文件,注意执行hello-openshift.yml对应的目录。
- hosts: localhost
gather_facts: false
vars_files:
- mysecrets
- myvars
tasks:
- name: Try to login to OCP cluster
k8s_auth:
host: "{{ ocp_master }}"
username: "{{ ocp_username }}"
password: "{{ ocp_password }}"
validate_certs: no
register: k8s_auth_result
- name: Create a Deployment by reading the definition from a local file
k8s:
namespace: testing
state: present
src: ~/ansible/hello-openshift.yml
api_key: "{{ k8s_auth_result.k8s_auth.api_key }}"
- 运行Ansible脚本。
$ ansible-playbook --vault-id=decrypt_passwd hello-deployment.yml
PLAY [localhost] ***********************************************************************************************************************************
TASK [Try to login to OCP cluster] ***********************************************************************************************************************************
ok: [localhost]
TASK [Create a k8s namespace] ***********************************************************************************************************************************
changed: [localhost]
TASK [Create a Deployment by reading the definition from a local file] ***********************************************************************************************************************************
changed: [localhost]
PLAY RECAP ***********************************************************************************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 确认对象创建成功。
oc get all -n testing
NAME READY STATUS RESTARTS AGE
pod/hello-openshift-5f5c9bc6f-9xvwv 1/1 Running 0 41s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hello-openshift 1/1 1 1 41s
NAME DESIRED CURRENT READY AGE
replicaset.apps/hello-openshift-5f5c9bc6f 1 1 1 41s
查看Pod对象列表
- 查看pod-list.yml文件,它使用了k8s_info查看Pod的名称。
- hosts: localhost
gather_facts: false
vars_files:
- mysecrets
- myvars
tasks:
- name: Try to login to OCP cluster
k8s_auth:
host: "{{ ocp_master }}"
username: "{{ ocp_username }}"
password: "{{ ocp_password }}"
validate_certs: no
register: k8s_auth_result
- name: Get a list of all pods from testing
k8s_info:
namespace: testing
api_key: "{{ k8s_auth_result.k8s_auth.api_key }}"
kind: Pod
register: pod_list
- name: Print pod list
debug:
msg: "pod_list: {{ pod_list | json_query('resources[*].metadata.name') }}"
- 执行命令运行pod-list.yml,然后查看输出的pod名称。
$ ansible-playbook --vault-id=decrypt_passwd pod-list.yml
。。。
TASK [Print pod list] **************************************************************************************************************************
ok: [localhost] =>
msg: 'pod_list: [''hello-openshift-5f5c9bc6f-9xvwv''] '
。。。
删除Pod
- 查看del-pod.yml文件。
- hosts: localhost
gather_facts: false
vars_files:
- mysecrets
- myvars
tasks:
- name: Try to login to OCP cluster
k8s_auth:
host: "{{ ocp_master }}"
username: "{{ ocp_username }}"
password: "{{ ocp_password }}"
validate_certs: no
register: k8s_auth_result
- name: Get a list of all pods from testing
k8s_info:
namespace: testing
api_key: "{{ k8s_auth_result.k8s_auth.api_key }}
kind: Pod
register: pod_list
- name: Delete pods
k8s:
state: absent
api_version: v1
kind: Pod
namespace: testing
api_key: "{{ k8s_auth_result.k8s_auth.api_key }}
name: "{{ item }}"
loop: "{{ pod_list | json_query('resources[*].metadata.name') }}"
- 执行命令运del-pod.yml脚本,删除pod。查看执行结果,注意当前的Pod已经被删除。
$ ansible-playbook --vault-id=decrypt_passwd del-pod.yml
。。。
TASK [Delete pods] ***********************************************************************************************************************************
changed: [localhost] => (item=hello-openshift-5f5c9bc6f-9xvwv)
。。。
- 查看pod,确认原有pod被删除。不过OpenShift会创建新的Pod替代它。
$ oc get pod
NAME READY STATUS RESTARTS AGE
hello-openshift-5f5c9bc6f-9xvwv 0/1 Terminating 0 64m
hello-openshift-5f5c9bc6f-mzvjs 0/1 ContainerCreating 0 6s
参考
https://docs.ansible.com/ansible/latest/modules/k8s_module.html