使用Kubespray自动化部署Kubernetes 1.13.1

前言

部署Kubernetes除了手动方式外,还有诸如Kubeadm、Kubespray、Breeze、Rancher、kargo等多种自动化方式。工具没有好坏之分,能干事、效率高就行。这里,笔者仍使用Kubespray部署当前K8s最新版本(用着真的很贴身),可自动化部署HA集群、可灵活定制开发、高稳定性等。

本篇将介绍如何在不用科学上网的背景下,快速自动化部署K8s集群。那么,开始吧!

初始化环境

环境说明

环境实在有限,只有一台机器,想玩HA集群也没环境啊

主机名 IP地址 角色
K8s 172.16.0.180 Master+node

 

环境为Centos 7系统,各节点配置hosts和hostname,如

cat /etc/hosts

172.16.0.180   K8s

关闭防火墙等

sed -i 's/SELINUX=*/SELINUX=disabled/' /etc/selinux/config

systemctl disable firewalld && systemctl stop firewalld

Kubernetes 1.8开始要求关闭系统的Swap交换分区,方法如下

swapoff -a && echo "vm.swappiness=0" >> /etc/sysctl.conf && sysctl -p && free –h

Docker从1.13版本开始调整了默认的防火墙规则,禁用了iptables filter表中FOWARD链,这样会引起Kubernetes集群中跨Node的Pod无法通信,在各个Docker节点执行下面的命令:

iptables -P FORWARD ACCEPT

配置ssh key 认证。确保本机也可以 ssh 连接,否则下面部署失败

ssh-keygen -t rsa -N ""

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

更新系统内核为 4.4.x , CentOS 默认为3.10.x

rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org

rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

yum --enablerepo=elrepo-kernel install -y kernel-lt kernel-lt-devel

grub2-set-default 0

重启系统

reboot

增加内核配置

vim /etc/sysctl.conf

# docker

net.bridge.bridge-nf-call-iptables = 1

net.bridge.bridge-nf-call-ip6tables = 1

使其内核配置生效

sysctl -p

安装kubespray

安装 centos的epel源

yum -y install epel-release

make缓存

yum clean all && yum makecache

安装软件,ansible 必须 >= 2.7

yum install -y python-pip python34 python-netaddr python34-pip ansible git

下载源码,当前kubespray项目的master分支默认安装k8s 1.13.1版本

git clone https://github.com/kubernetes-sigs/kubespray

安装 kubespray 依赖,若无特殊说明,后续操作均在~/kubespray目录下执行

cd kubespray

pip install -r requirements.txt

配置kubespray

复制一份配置文件

cp -rfp inventory/sample inventory/mycluster

修改配置文件 hosts.ini。

vim inventory/mycluster/hosts.ini

[all]

k8s ansible_host=k8s ip=172.16.0.180

[kube-master]

k8s

[etcd]

k8s

[kube-node]

k8s

[k8s-cluster:children]

kube-master

kube-node

[calico-rr]

修改配置文件all.yaml

vim inventory/mycluster/group_vars/all/all.yml

# 修改如下配置:

loadbalancer_apiserver_localhost: true

# 加载内核模块,否则 ceph, gfs 等无法挂载客户端

kubelet_load_modules: true

默认镜像从 gcr.io/google-containers 下载,由于墙的原因不能下载。这里我将k8s 1.13.1版本所必须的镜像push到了DockerHub上,方便大家下载使用。

# 下载镜像(该步骤可不用执行)

docker pull xiaoxu780/kube-proxy:v1.13.1

docker pull xiaoxu780/kube-controller-manager:v1.13.1

docker pull xiaoxu780/kube-scheduler:v1.13.1

docker pull xiaoxu780/kube-apiserver:v1.13.1

docker pull xiaoxu780/coredns:1.2.6

docker pull xiaoxu780/cluster-proportional-autoscaler-amd64:1.3.0

docker pull xiaoxu780/kubernetes-dashboard-amd64:v1.10.0

docker pull xiaoxu780/etcd:3.2.24

docker pull xiaoxu780/node:v3.1.3

docker pull xiaoxu780/ctl:v3.1.3

docker pull xiaoxu780/kube-controllers:v3.1.3

docker pull xiaoxu780/cni:v3.1.3

docker pull xiaoxu780/pause-amd64:3.1

修改镜像默认的repo地址,使用Calico三层网络,同时可以指定安装的k8s版本,参数为kube_version。编辑文件

vim inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml

kube_image_repo: "gcr.io/google-containers" //修改为kube_image_repo: "xiaoxu780"

修改配置文件main.yml,使用sed命令批量替换

sed -i 's/gcr\.io\/google_containers/xiaoxu780/g' roles/download/defaults/main.yml

sed -i 's/quay\.io\/coreos/xiaoxu780/g' roles/download/defaults/main.yml

sed -i 's/quay\.io\/calico/xiaoxu780/g' roles/download/defaults/main.yml

修改代码,使用NodePort方式访问Dashboard。

vim ./roles/kubernetes-apps/ansible/templates/dashboard.yml.j2

# ------------------- Dashboard Service ------------------- #

……

……

      targetPort: 8443

  type: NodePort    //添加这一行   

  selector:

k8s-app: kubernetes-dashboard

注意

如果是单节点部署K8s,Kubespray默认会创建2个coredns Pod,但Deployment中又用到了podAntiAffinity,因此会导致其中一个coredns pod pending,所以需要修改代码如下

vim ./roles/kubernetes-apps/ansible/templates/coredns-deployment.yml.j2

//注释掉以下几行代码

      affinity:

        #podAntiAffinity:

        #  requiredDuringSchedulingIgnoredDuringExecution:

        #  - topologyKey: "kubernetes.io/hostname"

        #    labelSelector:

        #      matchLabels:

        #        k8s-app: coredns{{ coredns_ordinal_suffix | default('') }}

或者在spec一行添加代码:

spec:

  replicas: 1   //指定pod为1个副本

安装K8s集群

 K8s高可用方案

Kubernetes的高可用,要解决的核心其实是kube-apiserver组件和etcd的高可用,其它组件在多节点模式下,本身拥有天然容灾性。

etcd高可用

etcd本身就支持集群模式,所以啥都不用考虑,只要保证节点数量足够,升级备份之类的事情,kubespray本身就支持多节点etcd部署。由于etcd采用Raft一致性算法,集群规模最好不要超过9个,推荐3,5,7,9个数量。具体看集群规模。如果性能不够,宁可多分配资源,也最好不要超过9个。

api 高可用

api的高可用,一般有2种思路。

各节点自己代理

使用这种方式,会在每个Node节点启动一个Nginx代理,然后由这个Nginx代理负载所有的master节点的api。master会访问自己节点下的api(localhost)。这是Kubespray部署的默认方式。

外置负载均衡

利用外部的负载均衡实现,例如阿里云的SLB或自建的HAproxy等。

将hyperkube和kubeadm包下载到所有k8s节点的/tmp/releases 目录下,为了避免科学上网,此处,我下载存放到了网盘上。

https://pan.baidu.com/s/1m2rF1dRXIZh_15OevTDbnA

执行部署命令

ansible-playbook -i inventory/mycluster/hosts.ini cluster.yml -b -v -k

运维经验

如果需要扩容Work节点,则修改hosts.ini文件,增加新增的机器信息。然后执行下面的命令:

ansible-playbook -i inventory/mycluster/hosts.ini scale.yml -b -v -k

将hosts.ini文件中的master和etcd的机器增加到多台,执行部署命令

ansible-playbook -i inventory/mycluster/hosts.ini cluster.yml -b -vvv

刪除节点,如果不指定节点就是刪除整个集群:

ansible-playbook -i inventory/mycluster/hosts.ini remove-node.yml -b -v

如果需要卸载,可以执行以下命令:

ansible-playbook -i inventory/mycluster/hosts.ini reset.yml -b –vvv

升级K8s集群,选择对应的k8s版本信息,执行升级命令。涉及文件为upgrade-cluster.yml。

ansible-playbook upgrade-cluster.yml -b -i inventory/mycluster/hosts.ini -e kube_version=vX.XX.XX -vvv

 登录Dashboard

登陆Dashboard 支持 kubeconfig 和 token 两种认证方式,kubeconfig 也依赖 token 字段,所以生成 token这一步是必不可少的。此处,我们获取集群管理员(拥有所有命名空间的 admin 权限)的token。

查看kubernetes-dashboard暴露的端口,如下所示,这里是31777端口。

# kubectl get svc --all-namespaces | grep kubernetes-dashboard

kube-system   kubernetes-dashboard   NodePort    10.233.34.183   <none>        443:31777/TCP            12h

获取admin的token

# kubectl -n kube-system describe $(kubectl -n kube-system get secret -n kube-system -o name | grep namespace) | grep token

Name:         namespace-controller-token-kmtg7

Type:  kubernetes.io/service-account-token

token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJuYW1lc3BhY2UtY29udHJvbGxlci10b2tlbi1rbXRnNyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJuYW1lc3BhY2UtY29udHJvbGxlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImQwYTI0N2JkLTEwY2EtMTFlOS1iYTFiLWEwMzY5ZjNmMDQwNCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTpuYW1lc3BhY2UtY29udHJvbGxlciJ9.v689nSk_SxDLWk5Mna0t9uITRE1Jy2mstZxeJfZmQmm2UsQ-vIm4ueUNtCoA-PNx49s9hic-Pn6PfqyWQQW_QQ1yLDjjp1wl4J3tdar8fBfuR7Zvm5aKw8kyRhfQzQQZgEKlgBEHaYyKicgVUwEupa3zevXdUTnLH8FudcOdWEwgCflCveHdkRwoy88pYPyL5wh2egEKpeDhzOEztULsi2g3tpdlyg_uQIaKJ1OBODJZz5PXVFMYyIk06SyciEOX0YxF3pH_uSlPqg4RxMaeTfPhlWTnFPlIjQ2juK4s0o2Tyg_sftLSXvd3QtOg3tBavRm3pzHISIPbtN7EZAyWZQ

在dashboard登录页面上使用上面输出中的那个非常长的字符串作为token登录,即可以拥有管理员权限操作整个kubernetes集群中的对象。当然您也可以将这串token加到admin用户的kubeconfig文件中,继续使用kubeconfig登录,两种认证方式任您选择。登录dashboard。

https://172.16.0.180:31777

注意

由于这里使用的HTTPS,并未使用证书,因此使用Google等浏览器会终止访问。建议使用firefox浏览器。

验证K8s集群

查看集群状态

# kubectl get nodes

NAME   STATUS   ROLES         AGE   VERSION

k8s    Ready    master,node   36m   v1.13.1

查看集群Pod状态

# kubectl get pods --all-namespaces

NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE

kube-system   calico-kube-controllers-687b7cc79c-knj87   1/1     Running   0          35m

kube-system   calico-node-7rj8c                          1/1     Running   0          35m

kube-system   coredns-5b47d4476c-8wdb7                   1/1     Running   0          35m

kube-system   coredns-5b47d4476c-92wnq                   1/1     Running   0          35m

kube-system   dns-autoscaler-5b547856bc-95cft            1/1     Running   0          35m

kube-system   kube-apiserver-k8s                         1/1     Running   0          36m

kube-system   kube-controller-manager-k8s                1/1     Running   0          36m

kube-system   kube-proxy-cdlzp                           1/1     Running   0          35m

kube-system   kube-scheduler-k8s                         1/1     Running   0          36m

kube-system   kubernetes-dashboard-d7978b5cc-lvf6l       1/1     Running   0          35m

查看ipvs

# ipvsadm -L -n

IP Virtual Server version 1.2.1 (size=4096)

Prot LocalAddress:Port Scheduler Flags

  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

TCP  172.16.0.180:32714 rr

  -> 10.233.65.133:8443           Masq    1      0          0         

TCP  172.17.0.1:32714 rr

  -> 10.233.65.133:8443           Masq    1      0          0         

TCP  10.233.0.1:443 rr

  -> 172.16.0.180:6443            Masq    1      5          0         

TCP  10.233.0.3:53 rr

  -> 10.233.65.131:53             Masq    1      0          0         

  -> 10.233.65.134:53             Masq    1      0          0         

TCP  10.233.0.3:9153 rr

  -> 10.233.65.131:9153           Masq    1      0          0         

  -> 10.233.65.134:9153           Masq    1      0          0         

TCP  10.233.45.198:443 rr

  -> 10.233.65.133:8443           Masq    1      0          0         

TCP  10.233.65.128:32714 rr

  -> 10.233.65.133:8443           Masq    1      0          0         

TCP  127.0.0.1:32714 rr

  -> 10.233.65.133:8443           Masq    1      0          0         

UDP  10.233.0.3:53 rr

  -> 10.233.65.131:53             Masq    1      0          0         

  -> 10.233.65.134:53             Masq    1      0          0

创建一个Nginx应用的deplpyment。K8s中,针对无状态类服务推荐使用Deployment,有状态类服务则建议使用Statefulset。RC和RS已不支持目前K8s的诸多新特性了。

# vim nginx-deployment.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: nginx-dm

spec:

  replicas: 3

  selector:

    matchLabels:

      name: nginx

  template:

    metadata:

      labels:

        name: nginx

    spec:

      containers:

        - name: nginx

          image: nginx:alpine

          imagePullPolicy: IfNotPresent

          ports:

            - containerPort: 80

              name: http

---



apiVersion: v1

kind: Service

metadata:

  name: nginx-svc

spec:

  ports:

    - port: 80

      name: http

      targetPort: 80

      protocol: TCP

  selector:

    name: nginx


# kubectl apply -f nginx-deployment.yaml

deployment.apps/nginx-dm created
service/nginx-svc created



# kubectl get pods

NAME                        READY   STATUS    RESTARTS   AGE

nginx-dm-799879696c-9cdgz   1/1     Running   0          30s

nginx-dm-799879696c-cwzn5   1/1     Running   0          30s

nginx-dm-799879696c-xwjd7   1/1     Running   0          30s



   

# kubectl get svc -o wide

NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR

kubernetes   ClusterIP   10.233.0.1      <none>        443/TCP   39m   <none>

nginx-svc    ClusterIP   10.233.42.172   <none>        80/TCP    65s   name=nginx



# ipvsadm -L -n

测试nginx服务是否正常

# curl -I 10.233.42.172

HTTP/1.1 200 OK

Server: nginx/1.15.8

Date: Sat, 05 Jan 2019 09:58:16 GMT

Content-Type: text/html

Content-Length: 612

Last-Modified: Wed, 26 Dec 2018 23:21:49 GMT

Connection: keep-alive

ETag: "5c240d0d-264"

Accept-Ranges: bytes

 后续

K8s从1.11版本起便废弃了Heapster监控组件,取而代之的是metrics-server 和 custom metrics API,后面将陆续完善包括Prometheus+Grafana监控,Kibana+Fluentd日志管理,cephfs-provisioner存储(可能需要重新build kube-controller-manager装上rbd相关的包才能使用Ceph RBD StorageClass),traefik ingress等服务。

参考资料

https://github.com/kubernetes-sigs/kubespray/blob/master/docs/getting-started.md

作者介绍

徐超,OpenStack云计算和Kubernetes爱好者、捣鼓者。

 

K8S中文社区微信公众号

评论 16

登录后评论

立即登录  

  1. #12

    老铁,你的xiaoxu780/kubernetes-dashboard-amd64:v1.10.1″下载不了

    shalai5年前 (2019-01-14)
  2. #11

    TASK [download : container_download | Download containers if pull is required or told to always pull (all nodes)] *********************************************************************
    Monday 14 January 2019 17:41:17 +0800 (0:00:00.050) 0:01:23.121 ********
    FAILED – RETRYING: container_download | Download containers if pull is required or told to always pull (all nodes) (4 retries left).
    FAILED – RETRYING: container_download | Download containers if pull is required or told to always pull (all nodes) (3 retries left).
    FAILED – RETRYING: container_download | Download containers if pull is required or told to always pull (all nodes) (2 retries left).
    FAILED – RETRYING: container_download | Download containers if pull is required or told to always pull (all nodes) (1 retries left).
    fatal: [k8s]: FAILED! => {“attempts”: 4, “changed”: true, “cmd”: [“/usr/bin/docker”, “pull”, “xiaoxu780/kubernetes-dashboard-amd64:v1.10.1”], “delta”: “0:00:02.966843”, “end”: “2019-01-14 17:41:53.812930”, “msg”: “non-zero return code”, “rc”: 1, “start”: “2019-01-14 17:41:50.846087”, “stderr”: “Error response from daemon: manifest for xiaoxu780/kubernetes-dashboard-amd64:v1.10.1 not found”, “stderr_lines”: [“Error response from daemon: manifest for xiaoxu780/kubernetes-dashboard-amd64:v1.10.1 not found”], “stdout”: “”, “stdout_lines”: []}

    NO MORE HOSTS LEFT ********************************************************************************************************************************************************************
    to retry, use: –limit @/root/kubespray/cluster.retry

    PLAY RECAP ****************************************************************************************************************************************************************************
    k8s : ok=152 changed=3 unreachable=0 failed=1
    localhost : ok=1 changed=0 unreachable=0 failed=0

    Monday 14 January 2019 17

    shalai5年前 (2019-01-14)
  3. #10

    应该playbook版本号跟上传的镜像版本号没对上

    shalai5年前 (2019-01-14)
  4. #9

    有几个镜像下载不来 kube-scheduler:v1.13.1 etcd

    啦啦啦啦啦5年前 (2019-01-15)
    • #!/bin/bash
      images=(kube-proxy-amd64:v1.11.1 kube-scheduler-amd64:v1.11.1 kube-controller-manager-amd64:v1.11.1
      kube-apiserver-amd64:v1.11.1 etcd-amd64:3.2.18 coredns:1.1.3 pause:3.1 )
      for imageName in ${images[@]} ; do
      docker pull anjia0532/google-containers.$imageName
      docker tag anjia0532/google-containers.$imageName k8s.gcr.io/$imageName
      docker rmi anjia0532/google-containers.$imageName
      done

      shalai5年前 (2019-01-16)
  5. #8
  6. #7

    可能是代码发生了变化,请将xiaoxu780/kubernetes-dashboard-amd64:v1.10.1 改为xiaoxu780/kubernetes-dashboard-amd64:v1.10.0

    xuchao5年前 (2019-01-18)
    • 请问这个镜像的修改是在那个目录文件加

      changpaozhe5年前 (2019-02-18)
    • 请问这个如何修改

      changpaozhe5年前 (2019-02-18)
  7. #6

    有几个镜像下载不来 kube-scheduler:v1.13.1 etcd 问题
    因这些镜像是在国外dockerhub上,虽可以访问,但是网速很慢,可以多尝试几次pull

    xuchao5年前 (2019-01-18)
  8. #5

    改了dashoboard的版本号 xiaoxu780/ctl:v3.1.3这个镜像找不到,能麻烦上次一下吗

    遗忘5年前 (2019-01-22)
  9. #4

    TASK [download : file_download | Download item] **********************************************
    Saturday 26 January 2019 04:35:55 -0500 (0:00:00.301) 0:14:11.258 ******
    FAILED – RETRYING: file_download | Download item (4 retries left).
    FAILED – RETRYING: file_download | Download item (3 retries left).
    FAILED – RETRYING: file_download | Download item (2 retries left).
    FAILED – RETRYING: file_download | Download item (1 retries left).
    fatal: [k8s]: FAILED! => {“attempts”: 4, “changed”: false, “msg”: “Failed to connect to storage.googleapis.com at port 443: [Errno 104] Connection reset by peer”}

    NO MORE HOSTS LEFT ***************************************************************************
    to retry, use: –limit @/root/kubespray/cluster.retry

    PLAY RECAP ***********************************************************************************
    k8s : ok=140 changed=4 unreachable=0 failed=1
    localhost : ok=1 changed=0 unreachable=0 failed=0

    wyp5年前 (2019-01-26)
  10. #3

    这篇文章很好,对我帮助很大,如果有完整的镜像就完美了!

    wyp5年前 (2019-01-28)
  11. #2

    可以提供一下镜像吗,这篇对我帮助非常大,感谢了!

    初学者5年前 (2019-02-13)
  12. #1

    问下,对于 kubespray 安装的 k8s,在日志收集这块其 pod 的 timezone 是怎么修改的??我这边使用 podpreset 来测试普通的 pod 是正常的,但是好像对 apiserver、scheduler 等这类系统组件的 pod 不起作用,timezone 始终没法改变;我也尝试了修改 /etc/kubernetes/manifest/*.yaml 文件来挂载本地节点的 /etc/localtime 文件,也还是不起作用。不知道楼主对这块有啥方法没?

    jasontom5年前 (2019-04-06)