上一篇博客记录了一下在 CentOS 下搭建 k8s 环境的方式,主要是使用的 shell 脚本执行安装部署命令。但是执行脚本终究只能人工执行,而且无法大批量安装,而本篇博客就使用批量执行工具 ansible 来自动化安装 k8s 环境。

步骤梳理

首先在介绍 ansible 编排之前,先梳理一下搭建 k8s 环境的步骤(之前的 shell 脚本部署方式有详细步骤注释)。

  1. 所有节点安装 docker-ce
  2. 所有节点配置 k8s 环境
  3. master 节点安装 k8s,并启动 flannel 服务
  4. node 节点安装 k8s,并执行 join 到主节点的命令

我将整个安装步骤分为这4个步骤,于是我的 ansible-playbook 里面的 roles 也是分成4个 role 来执行任务。

代码结构

代码结构基本是按照 ansible-playbook 的结构来的,上面安装的四个步骤对应的就是 roles 下面的四个目录:docker、k8s_env、k8s_master、k8s_node,具体的文件作用可以看注释。

项目代码已经提交到 GitHub 仓库,地址为:https://github.com/Hopetree/k8s

+----deploy
|    +----ansible.cfg
|    +----group_vars
|    |    +----all.yml                         # 部署所需参数
|    +----hosts                                # 节点信息
|    +----k8s_install.yml                      # 执行文件
|    +----roles
|    |    +----docker                          # 安装docker
|    |    |    +----tasks
|    |    |    |    +----main.yml
|    |    |    +----templates
|    |    |    |    +----daemon.json.j2
|    |    +----k8s_env                         # 配置k8s环境
|    |    |    +----tasks
|    |    |    |    +----main.yml
|    |    |    +----templates
|    |    |    |    +----k8s.conf.j2
|    |    +----k8s_master                      # 主节点安装k8s
|    |    |    +----files
|    |    |    |    +----kube-flannel.yml
|    |    |    +----tasks
|    |    |    |    +----main.yml
|    |    |    +----templates
|    |    |    |    +----kubernetes.repo.j2
|    |    +----k8s_node                        # node节点安装k8s
|    |    |    +----tasks
|    |    |    |    +----main.yml
|    |    |    +----templates
|    |    |    |    +----kubernetes.repo.j2

然后看一下执行文件 k8s_install.yml 中是如何对每个步骤执行机进行划分的:

---
- hosts: k8s
  roles:
    - role: docker
      become: yes
    - role: k8s_env
      become: yes

- hosts: master
  roles:
    - role: k8s_master
      become: yes

- hosts: node
  roles:
    - role: k8s_node
      become: yes

其实划分执行机很简单,我在 hosts 里面配置了执行机分类,k8s 就是所有节点,master 就是主节点,node 就是 node 节点,所有使用 hosts 来控制每个步骤的执行机。

安装流程

安装 docker(所有节点)

安装 docker 的步骤跟之前 shell 脚本的流程一样,只不过把原理的命令行形式改成 ansible 的模块来编排即可,代码如下:

---
- name: uninstall docker
  yum: name={{ docker.remove_list }} state=absent

- name: rm docker dir
  file: path={{ item }} state=absent
  with_items:
    - /var/lib/docker
    - /var/run/docker

- name: install yum-utils
  yum: name=yum-utils state=present

- name: add docker repo
  shell: yum-config-manager --add-repo {{ docker.repo }}

- name: install docker-ce
  yum: name={{ docker.version }} state=present update_cache=True

- name: set docker registry mirrors
  template: src=daemon.json.j2 dest=/etc/docker/daemon.json

- name: start docker service
  systemd: name=docker enabled=yes daemon_reload=yes state=started

可以把这个 yaml 文件里面的编排步骤跟之前的 shell 脚本作对比,可以发现基本是每个 shell 命令的操作对应了一个 ansible 步骤。

配置 k8s 环境信息(所有节点)

配置 k8s 环境信息的任务是 k8s_env,具体编排如下:

---
- name: stop firewalld
  systemd: name=firewalld state=stopped enabled=no

- name: disabled selinux
  shell: "setenforce 0 && sed -i 's/SELINUX=permissive/SELINUX=disabled/' /etc/sysconfig/selinux;sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config"

- name: swap off
  shell: "swapoff -a && sed -i 's/.*swap.*/#&/' /etc/fstab"

- name: set k8s conf
  template: src=k8s.conf.j2 dest=/etc/sysctl.d/k8s.conf

- name: sysctl --system
  shell: sysctl --system

其实这里的 sed 命令可以使用 replace 模块来编排,我这里保留了 shell 命令行。

主节点安装 k8s

执行编排如下:

---
- name: copy flannel file
  copy: src=kube-flannel.yml dest={{ k8s.flannel.path }}

- name: change image url for flannel file
  replace: path={{ k8s.flannel.path }} regexp="quay\.io" replace={{ k8s.flannel.image_url }}

- name: set k8s repo
  template: src=kubernetes.repo.j2 dest=/etc/yum.repos.d/kubernetes.repo

- name: uninstall kubectl kubeadm kubelet
  yum: name=kubectl,kubeadm,kubelet state=absent

- name: install kubectl
  yum: name={{ k8s.kubectl }} state=present

- name: install kubelet
  yum: name={{ k8s.kubelet }} state=present

- name: install kubeadm
  yum: name={{ k8s.kubeadm }} state=present

- name: set systemd for kubelet
  systemd: name=kubelet enabled=yes daemon_reload=yes state=started

- name: init kubeadm
  shell: "kubeadm init --image-repository {{ k8s.image_repository }} --kubernetes-version {{ k8s.version }} --apiserver-advertise-address {{ ansible_ssh_host }} --pod-network-cidr={{ k8s.pod_netword }}/16 --token-ttl 0"

- name: copy kube config
  shell: "mkdir -p $HOME/.kube && sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config && sudo chown $(id -u):$(id -g) $HOME/.kube/config"

- name: apply flannel
  shell: "kubectl apply -f {{ k8s.flannel.path }}"

在安装 kubelet 和 kubeadm 的时候,我遇到了问题,就是我之前是先安装的 kubeadm 后安装的 kubelet,然后一直导致 kubelet 的安装版本跟我设置的版本不一样,导致最终 k8s 初始化失败。

后来我查看代码执行输出才发现问题,原因是 kubeadm 的安装依赖于 kubelet,所以如果先安装 kubeadm,那么程序会自动安装一个版本(目测是最新的)的 kubelet,于是后面执行 kubelet 安装的时候因为前面自动安装了,所有会忽略掉,这就是最终导致安装的版本跟自己设置的版本不一样的原因。这也给我一个意识,就是如果要安装多个软件,如果软件之前有依赖关系,应该先安装被依赖的软件。

node 节点安装 k8s

看过之前手动部署 k8s 的文章应该记得一个步骤:当 node 节点安装完 k8s 之后需要执行 join 主机点集群的命令,而这个命令需要去主节点查询得到,所有当时是手动查询然后执行的。所以 ansible 如何做到在当前执行机操作步骤的时候到另外的执行机执行步骤,我当时查到了一种方案就是使用 delegate_to 参数,在模块中添加这个参数,就可以将该步骤到这个参数指向的 IP 主机上面执行步骤。我这做的就是去主节点查询命令,然后注册成一个键值对给后面的步骤使用。

---
- name: set k8s repo
  template: src=kubernetes.repo.j2 dest=/etc/yum.repos.d/kubernetes.repo

- name: uninstall kubectl kubeadm kubelet
  yum: name=kubeadm,kubelet state=absent

- name: install kubelet
  yum: name={{ k8s.kubelet }} state=present

- name: install kubeadm
  yum: name={{ k8s.kubeadm }} state=present

- name: set systemd for kubelet
  systemd: name=kubelet enabled=yes daemon_reload=yes state=started

- name: query kubeadm join command
  shell: kubeadm token create --print-join-command
  register: kubeadm_join_cmd
  delegate_to: "{{ k8s.master_ip }}"        # 在主节点上面执行这个任务

- name: print cmd
  debug:
    var: kubeadm_join_cmd.stdout

- name: join k8s
  shell: "{{ kubeadm_join_cmd.stdout }}"

整个任务运行的命令是:

ansible-playbook k8s_install.yml -i hosts -u alex -k -K -v

执行结果如下:

PLAY RECAP ************************************************************************************************************
k8s-master     : ok=25   changed=20   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
k8s-node01     : ok=22   changed=17   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
k8s-node02     : ok=22   changed=17   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

所有步骤都没有报错之后可以查询 k8s 集群状态,最开始可能会发现只有主节点是 Ready,node 节点还是 NotReady 状态,这是正常的,因为之前的文章说过,node 节点需要拉取 flannel 镜像启动容器,比较慢,所有需要等一段时间。

过一段时间再查询状态可以看到所有节点都是准备好了:

[root@k8s-master alex]# kubectl get pods -o wide -n kube-system
NAME                                 READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
coredns-58cc8c89f4-jsgjh             1/1     Running   0          4h56m   10.244.2.3       k8s-node02   <none>           <none>
coredns-58cc8c89f4-z4zhn             1/1     Running   0          4h56m   10.244.2.2       k8s-node02   <none>           <none>
etcd-k8s-master                      1/1     Running   0          4h55m   192.168.31.76    k8s-master   <none>           <none>
kube-apiserver-k8s-master            1/1     Running   0          4h55m   192.168.31.76    k8s-master   <none>           <none>
kube-controller-manager-k8s-master   1/1     Running   0          4h56m   192.168.31.76    k8s-master   <none>           <none>
kube-flannel-ds-amd64-2sg2q          1/1     Running   0          4h56m   192.168.31.76    k8s-master   <none>           <none>
kube-flannel-ds-amd64-fwtvr          1/1     Running   0          4h55m   192.168.31.133   k8s-node01   <none>           <none>
kube-flannel-ds-amd64-sph6k          1/1     Running   0          4h55m   192.168.31.178   k8s-node02   <none>           <none>
kube-proxy-b9tp5                     1/1     Running   0          4h55m   192.168.31.178   k8s-node02   <none>           <none>
kube-proxy-tnfpq                     1/1     Running   0          4h55m   192.168.31.133   k8s-node01   <none>           <none>
kube-proxy-znf9h                     1/1     Running   0          4h56m   192.168.31.76    k8s-master   <none>           <none>
kube-scheduler-k8s-master            1/1     Running   0          4h55m   192.168.31.76    k8s-master   <none>           <none>
[root@k8s-master alex]# kubectl get nodes
NAME         STATUS   ROLES    AGE     VERSION
k8s-master   Ready    master   4h57m   v1.16.0
k8s-node01   Ready    <none>   4h55m   v1.16.0
k8s-node02   Ready    <none>   4h55m   v1.16.0

总结:使用 ansible 工具不仅可以将手动操作自动化,从而减少手动操作中漏掉或者重复执行步骤的问题,更重要的是可以批量执行任务,当 k8s 集群规模比较大的时候,手动部署肯定是不可行的,此时 ansible 就能发挥它批量部署的能力。

版权声明:如无特殊说明,文章均为本站原创,转载请注明出处

本文链接:https://tendcode.com/article/k8s_install-k8s-by-ansible/

许可协议:署名-非商业性使用 4.0 国际许可协议