0%

部署 Kubernetes 也能如此简单吗?

关于 Kubernetes 系列其他文章的传送门

  1. 《 部署 Kubernetes 也能如此简单吗? 》     您当前所在位置

  2. 《 初识 k8s,新时代的宠儿 》

  3. 《 深度学习 Pod 》

  4. 《 学会这 5 种 Pod 控制器,搞定发布、更新、回滚,从此告别人肉运维!! 》

  5. 《 k8s 中的网络入口 – Service 资源管理 》

  6. 《 k8s 中的 7 层调度 – Ingress 》

  7. 《 k8s 中的存储系统 – Volumes 》

  8. 《 k8s 中强大的配置中心 – ConfigMap 》

  9. 《 k8s 中的部署神器 – Statefulset 控制器 》

  10. 《 k8s 中的安全守护神 – 你不知道不代表它不在 》

  11. 《 k8s 中的图形接口 – Dashboard 》

  12. 《 k8s 中的网络插件 – flannel 和 Calico 》

  13. 《 k8s 中的调度器 – 亲和性、污点和容忍性 》

  14. 《 k8s 中对资源的监控 – 资源指标、Prometheus、弹性伸缩器 HPA 》

  15. 《 k8s 中的云原生应用管理利器 – Helm 》

  16. 《 理解 k8s 高可用,让你的集群稳如泰山 》



logo

一、主机环境预设

Kubernetes 技术已经成为了原生云技术的事实标准,它是目前基础软件领域最为热门的分布式调度和管理平台。于是,Kubernetes 也几乎成了时下开发工程师和运维工程师必备的技能之一。

测试环境基准

测试使用的 Kubernetes 集群可由一个 master 主机及一个以上(建议至少两个)node 主机组成,这些主机可以是物理服务器,也可以运行于 vmware、virtualbox 或 kvm 等虚拟化平台上的虚拟机,甚至是公有云上的 VPS 主机。

本测试环境将由 master01node01node02 三个独立的主机组成,它们分别拥有 4 核心的 CPU 及 4G 的内存资源,操作系统环境均为 CentOS 7.5 1804,域名为 ilinux.io。此外,各主机需要预设的系统环境如下:

  1. 借助于 chrony 服务设定各节点时间精确同步;
  2. 通过 DNS 完成各节点的主机名称解析,测试环境主机数量较少时也可以使用 hosts 文件进行;
  3. 关闭各节点的 iptables 或 firewalld 服务,并确保它们被禁止随系统引导过程启动;
  4. 各节点禁用 SELinux;
  5. 各节点禁用所有的 Swap 设备;
  6. 若要使用 ipvs 模型的 proxy,各节点还需要载入 ipvs 相关的各模块。

1、设定时钟同步

若节点可直接访问互联网,直接启动 chronyd 系统服务,并设定其随系统引导而启动。

1
2
~]# systemctl start chronyd.service
~]# systemctl enable chronyd.service

不过,建议用户配置使用本地的的时间服务器,在节点数量众多时尤其如此。存在可用的本地时间服务器时,修改节点的 /etc/crhony.conf 配置文件,并将时间服务器指向相应的主机即可,配置格式如下:

1
server CHRONY-SERVER-NAME-OR-IP iburst

2、主机名称解析

出于简化配置步骤的目的,本测试环境使用 hosts 文件进行各节点名称解析,文件内容如下所示:

1
2
3
172.20.0.71 master01.ilinux.io master01
172.20.0.61 node01.ilinux.io node01
172.20.0.62 node02.ilinux.io node02

3、关闭 iptables 或 firewalld 服务

在 CentOS7 上,iptables 或 firewalld 服务通常只会安装并启动一种,在不确认具体启动状态的前提下,这里通过同时关闭并禁用二者即可简单达到设定目标。

1
2
3
4
~]# systemctl stop firewalld.service 
~]# systemctl stop iptables.service
~]# systemctl disable firewalld.service
~]# systemctl disable iptables.service

4、关闭并禁用 SELinux

若当前启用了 SELinux,则需要编辑 /etc/sysconfig/selinux 文件,禁用 SELinux,并临时设置其当前状态为 permissive

1
2
~]# sed -i 's@^\(SELINUX=\).*@\1disabled@' /etc/sysconfig/selinux
~]# setenforce 0

5、禁用 Swap 设备

部署集群时,kubeadm 默认会预先检查当前主机是否禁用了 Swap 设备,并在未禁用时强制终止部署过程。因此,在主机内存资源充裕的条件下,需要禁用所有的 Swap 设备,否则,就需要在后文的 kubeadm initkubeadm join 命令执行时额外使用相关的选项忽略检查错误。

关闭 Swap 设备,需要分两步完成。首先是关闭当前已启用的所有 Swap 设备:

1
~]# swapoff -a

而后编辑 /etc/fstab 配置文件,注释用于挂载 Swap 设备的所有行。

6、启用 ipvs 内核模块

创建内核模块载入相关的脚本文件 /etc/sysconfig/modules/ipvs.modules,设定自动载入的内核模块。文件内容如下:

1
2
3
4
5
6
7
8
#!/bin/bash
ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs"
for mod in $(ls $ipvs_mods_dir | grep -o "^[^.]*"); do
/sbin/modinfo -F filename $mod &> /dev/null
if [ $? -eq 0 ]; then
/sbin/modprobe $mod
fi
done

修改文件权限,并手动为当前系统加载内核模块:

1
2
~]# chmod +x /etc/sysconfig/modules/ipvs.modules 
~]# bash /etc/sysconfig/modules/ipvs.modules

二、安装程序包

注意:在各主机上完成如下设定

1、生成 yum 仓库配置

均使用阿里云的镜像站。

首先获取 docker-ce 的配置仓库配置文件:

1
~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker.repo

而后手动生成 kubernetes 的 yum 仓库配置文件 /etc/yum.repos.d/kubernetes.repo,内容如下:

1
2
3
4
5
6
7
8
9
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

2、安装相关的程序包

Kubernetes 会对经过充分验正的 Docker 程序版本进行认证,在 k8s 官方的发布页可以查到相关信息。目前认证完成的最高版本是 17.03,但 docker-ce 的最新版本已经高出了几个版本号。管理员可忽略此认证而直接使用最新版本的 docker-ce 程序。不过,还是建议使用经过验证的 Docker 版本。

安装最新版:

1
2
~]# yum install docker-ce 
~]# yum install kubelet kubeadm kubectl

如果要安装目前经过 Kubernetes 认证的 docker-17 17.03 版,可以将上面第一条安装命令替换为如下命令:

1
~]# yum install -y --setopt=obsoletes=0 docker-ce-17.03.2.ce docker-ce-selinux-17.03.2.ce

三、启动 docker 服务

注意:在各主机上完成如下设定

代理

若要通过默认的 k8s.gcr.io 镜像仓库获取 Kubernetes 系统组件的相关镜像,需要配置 docker Unit File 文件:

  • /usr/lib/systemd/system/docker.service 中的 Environment 变量,为其定义能用的 HTTPS_PROXY,格式如下:
1
2
Environment="HTTPS_PROXY=PROTOCOL://HOST:PORT"
Environment="NO_PROXY=127.0.0.0/8,172.20.0.0/16"

实际使用:

1
2
Environment="HTTPS_PROXY=http://www.ik8s.io:10070"
Environment="NO_PROXY=192.168.0.0/16,127.0.0.0/8"

更改 FORWARD 链规则

另外,docker 自 1.13 版起会自动将 iptables 的 FORWARD 默认策略为 DROP,这可能会影响 Kubernetes 集群依赖的报文转发功能。因此,需要在 docker 服务启动后,重新将 FORWARD 链的默认策略设备为 ACCEPT

方式是修改 /usr/lib/systemd/system/docker.service 文件,在 ExecStart=/usr/bin/dockerd 一行之后新增一行如下内容:

1
ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT

启动 Docker

重载完成后即可启动 docker 服务:

1
2
~]# systemctl daemon-reload        
~]# systemctl start docker.service

而后设定 docker 和 kubelet 随系统引导自动启动:

1
~]# systemctl enable docker kubelet

保证在 sysctl 的配置中关于桥接的部分,被设为 1

1
2
3
4
5
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

使用 Docker info 命令可验证,如设定不对会有报错提示。

四、初始化主节点

注意:只在 master01 节点上完成如下操作

1、初始化 master 节点

若未禁用 Swap 设备,则需要编辑 kubelet 的配置文件 /etc/sysconfig/kubelet,设置其忽略 Swap 启用的状态错误,内容如下:

1
KUBELET_EXTRA_ARGS="--fail-swap-on=false"

(可选步骤)而后,在运行初始化命令之前先运行如下命令单独获取相关的镜像文件,而后再运行后面的 kubeadm init 命令,以便于观察到镜像文件的下载过程。

1
~]# kubeadm config images pull

最后就可以通过 kubeadm init 命令进行 master 节点的初始化了,支持两种初始化方式:

  • 通过命令行选项传递关键的部署设定;
  • (建议)基于 yaml 格式的专用配置文件,这种允许用户自定义各个部署参数。

下面分别给出了两种实现方式的配置步骤。

建议读者采用第二种方式进行。

另外,kubeadm init 命令完整参考指南请移步官方文档。
https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/

注意事项

对于 Kubernetes 系统的新用户来说,无论使用哪种方法初始化,命令运行结束后,请另外新建一个文本文件,记录最后输出的 kubeadm join ...... 命令,因为它提示了后续需要的操作步骤,类似这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Your Kubernetes master has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

kubeadm join 172.20.0.71:6443 --token gwxgdg.igg5728t1vt8ahhx --discovery-token-ca-cert-hash sha256:9b63cd1530b50da4733d2e7dace9270782211e25ec2e4bbac395e59adc56a26c

初始化方式一

运行如下命令完成 master01 节点的初始化:

1
~]# kubeadm init --kubernetes-version=v1.13.3 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --ignore-preflight-errors=Swap

可使用 --dry-run 测试安装一下。

命令中的各选项简单说明如下:

  • --kubernetes-version:此选项的版本号用于指定要部署的 Kubenretes 程序版本,它需要与当前安装的 kubeadm 版本保持一致;
  • --pod-network-cidr:此选项用于指定为 Pod 分配使用的网络地址,它通常应该与要部署使用的网络插件(例如 flannel、calico 等)的默认设定保持一致,10.244.0.0/16 是 flannel 默认使用的网络;
  • --service-cidr:用于指定为 Service 分配使用的网络地址,它由 kubernetes 管理,默认即为 10.96.0.0/12
  • --ignore-preflight-errors=Swap 仅应该在未禁用 Swap 设备的状态下使用。

初始化方式二

kubeadm 也可通过配置文件加载配置,以定制更丰富的部署选项。以下是个符合前述命令设定方式的使用示例。

不过,它明确定义了 kubeProxy 的模式为 ipvs,并支持通过修改 imageRepository 的值修改获取系统镜像时使用的镜像仓库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.13.3 # 需要与当前安装的 kubeadm 版本保持一致
api:
advertiseAddress: 172.20.0.71
bindPort: 6443
controlPlaneEndpoint: ""
imageRepository: k8s.gcr.io
kubeProxy:
config:
mode: "ipvs"
ipvs:
ExcludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
syncPeriod: 30s
kubeletConfiguration:
baseConfig:
cgroupDriver: cgroupfs
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
failSwapOn: false
resolvConf: /etc/resolv.conf
staticPodPath: /etc/kubernetes/manifests
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12

将上面的内容保存于配置文件中,例如 kubeadm-config.yaml,而后执行相应的命令:

1
~]# kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=Swap

2、初始化 kubectl

kubectl 是 kube-apiserver 的命令行客户端程序,实现了除系统部署之外的几乎全部的管理操作,是 kubernetes 管理员使用最多的命令之一。

kubectl 需经由 API server 认证及授权后方能执行相应的管理操作,kubeadm 部署的集群为其生成了一个具有管理员权限的认证配置文件 /etc/kubernetes/admin.conf,它可由 kubectl 通过默认的 $HOME/.kube/config 的路径进行加载。

当然,用户也可在 kubectl 命令上使用 --kubeconfig 选项指定一个别的位置。

下面复制认证为 Kubernetes 系统管理员的配置文件至目标用户(例如当前用户 root)的家目录下:

1
2
~]# mkdir ~/.kube 
~]# cp /etc/kubernetes/admin.conf ~/.kube/config

而后,即可通过 kubectl 进行客户端命令测试,并借此了解集群组件的当前状态:

1
~]# kubectl get componentstatus

一个正常的输出应该类似如下输出结果所示:

1
2
3
4
NAME                 STATUS    MESSAGE              ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health": "true"}

3、添加 flannel 网络附件

flannel 的 Github 地址:https://github.com/coreos/flannel

Kubernetes 系统上 Pod 网络的实现依赖于第三方插件进行,这类插件有近数十种之多,较为著名的有 flannelcalicocanalkube-router 等,简单易用的实现是为 CoreOS 提供的 flannel 项目。下面的命令用于在线部署 flannel 至 Kubernetes 系统之上:

1
~]# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

而后使用如下命令确认其输出结果中 Pod 的状态为 Running,类似如下所示:

1
2
3
~]# kubectl get pods -n kube-system -l app=flannel
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-amd64-wscnz 1/1 Running 0 14m

而后使用如下命令确认其输出结果中,所有的 Pod 的状态均为 Running

1
~]# kubectl get pods -n kube-system

4、验正 master 节点已经就绪

1
~]# kubectl get nodes

上述命令应该会得到类似如下输出:

1
2
NAME                 STATUS   ROLES    AGE    VERSION
master01.ilinux.io Ready master 4m9s v1.13.3

五、添加节点到集群中

注意:在 node01node02 上分别完成如下操作

1、禁用 Swap

若未禁用 Swap 设备,编辑 kubelet 的配置文件 /etc/sysconfig/kubelet,设置其忽略 Swap 启用的状态错误,内容如下:

1
KUBELET_EXTRA_ARGS="--fail-swap-on=false"

2、将 Node 节点加入集群

将节点加入第二步中创建的 master 的集群中。

要使用主节点初始化过程中记录的 kubeadm join 命令,并且在未禁用 Swap 设备的情况下,额外附加 --ignore-preflight-errors=Swap 选项。

注意
添加过程需要访问 Google 的网站下载镜像,但是因为某种不可抗力的原因,访问不稳定,所以最好等到一个节点完全安装好后,再进行下一个节点的安装。
可以在 Master 节点使用以下命令查看是否安装完毕,kubectl get pods -n kube-system
在确认所有 pod 已经下载好并 Running 后,再进行下一个节点的添加。

每个人的命令都不一样,在 Node 节点,执行主节点初始化过程中最后的命令,类似如下:

1
~]# kubeadm join 172.20.0.71:6443 --token gwxgdg.igg5728t1vt8ahhx --discovery-token-ca-cert-hash sha256:9b63cd1530b50da4733d2e7dace9270782211e25ec2e4bbac395e59adc56a26c --ignore-preflight-errors=Swap

3、验证

在每个节点添加完成后,即可通过 kubectl 验正添加结果。下面的命令及其输出是在 node01node02 均添加完成后运行的,其输出结果表明两个 Node 已经准备就绪。

1
2
3
4
5
~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01.monster.com Ready master 31m v1.13.3
node01.monster.com Ready <none> 3m8s v1.13.3
node02.monster.com Ready <none> 2m25s v1.13.3

到此为止,一个 master,并附带有两个 node 的 kubernetes 集群基础设施已经部署完成,用户随后即可测试其核心功能。

例如,下面的命令可将 myapp 镜像以 Pod 的形式编排运行于集群之上,并通过在集群外部进行访问:

1
2
~]# kubectl create deployment myapp --image=ikubernetes/myapp:v1
~]# kubectl create service nodeport myapp --tcp=80:80

而后,使用如下命令了解 Service 对象 myapp 使用的 NodePort,以便于在集群外部进行访问:

1
2
3
~]# kubectl get svc -l app=myapp
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myapp NodePort 10.102.254.75 <none> 80:31257/TCP 2m32s

myapp 是一个 web 应用,因此用户可以于集群外部通过 http://NodeIP:31257 这个 URL 访问 myapp 上的应用,例如于集群外通过浏览器访问 http://172.20.0.61:31257