服务器说明

节点要求

节点数 >=3台
CPU >=2
Memory >=2G
安全组:关闭(允许节点之间任意端口访问,以及ipip隧道协议通讯)

演示环境说明

系统类型IP地址节点角色CPUMemoryHostname
centos-7.5172.16.15.8master>=2>=2Gnode1
centos-7.5172.16.15.9master>=2>=2Gnode2
centos-7.5172.16.15.10worker>=2>=2Gnode3

系统设置(所有节点)

主机名

主机名必须合法,并且每个节点都不一样(建议命名规范:数字+字母+中划线组合,不要包含其他特殊字符)

# 查看主机名
$ hostname
# 修改主机名
$ hostnamectl set-hostname <your_hostname>

关闭防火墙、selinux、swap,重置iptables

# 关闭selinux
$ setenforce 0
$ sed -i '/SELINUX/s/enforcing/disabled/' /etc/selinux/config
# 关闭防火墙
$ systemctl stop firewalld && systemctl disable firewalld

# 设置iptables规则
$ iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat && iptables -P FORWARD ACCEPT
# 关闭swap
$ swapoff -a && free –h

# 关闭dnsmasq(否则可能导致容器无法解析域名)
$ service dnsmasq stop && systemctl disable dnsmasq

k8s参数设置

# 制作配置文件
$ cat > /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.ip_forward = 1
vm.swappiness = 0
vm.overcommit_memory = 1
EOF
# 生效文件
$ sysctl -p /etc/sysctl.d/kubernetes.conf

移除docker相关软件包(可选)

$ yum remove -y docker*
$ rm -f /etc/docker/daemon.json

使用kubespray部署集群

这部分只需要在一个操作节点执行,可以是集群中的一个节点,也可以是集群之外的节点。甚至可以是你自己的笔记本电脑。我们这里使用更普遍的集群中的任意一个linux节点。

配置免密

使操作节点可以免密登录到所有节点

# 1. 生成keygen(执行ssh-keygen,一路回车下去)
$ ssh-keygen
# 2. 查看并复制生成的pubkey
$ cat /root/.ssh/id_rsa.pub
# 3. 分别登陆到每个节点上,将pubkey写入/root/.ssh/authorized_keys
$ mkdir -p /root/.ssh
$ echo "<上一步骤复制的pubkey>" >> /root/.ssh/authorized_keys

依赖软件下载、安装

# 安装基础软件
$ yum install -y epel-release python36 python36-pip git
# 下载kubespray源码
$ wget https://github.com/kubernetes-sigs/kubespray/archive/v2.15.0.tar.gz
# 解压缩
$ tar -xvf v2.15.0.tar.gz && cd kubespray-2.15.0
# 安装requirements
$ cat requirements.txt
$ pip3.6 install -r requirements.txt

## 如果install遇到问题可以先尝试升级pip
## $ pip3.6 install --upgrade pip

生成配置

项目中有一个目录是集群的基础配置,示例配置在目录inventory/sample中,我们复制一份出来作为自己集群的配置

# copy一份demo配置,准备自定义
$ cp -rpf inventory/sample inventory/mycluster

# 国内能否安装的关键
cp inventory/mycluster/group_vars/all/offline.yml inventory/mycluster/group_vars/all/mirror.yml
sed -i -E '/# .*\{\{ files_repo/s/^# //g' inventory/mycluster/group_vars/all/mirror.yml
tee -a inventory/mycluster/group_vars/all/mirror.yml <<EOF
gcr_image_repo: "gcr.m.daocloud.io"
kube_image_repo: "k8s.m.daocloud.io"
docker_image_repo: "docker.m.daocloud.io"
quay_image_repo: "quay.m.daocloud.io"
github_image_repo: "ghcr.m.daocloud.io"
files_repo: "https://files.m.daocloud.io"
EOF

由于kubespray给我们准备了py脚本,可以直接根据环境变量自动生成配置文件,所以我们现在只需要设定好环境变量就可以啦

# 使用真实的hostname(否则会自动把你的hostname改成node1/node2...这种哦)
$ export USE_REAL_HOSTNAME=true
# 指定配置文件位置
$ export CONFIG_FILE=inventory/mycluster/hosts.yaml
# 定义ip列表(你的服务器内网ip地址列表,3台及以上,前两台默认为master节点)
$ declare -a IPS=(10.155.19.223 10.155.19.64 10.155.19.147)
# 生成配置文件
$ python3 contrib/inventory_builder/inventory.py ${IPS[@]}

个性化配置

配置文件都生成好了,虽然可以直接用,但并不能完全满足大家的个性化需求,比如用docker还是containerd?docker的工作目录是否用默认的/var/lib/docker?等等。当然默认的情况kubespray还会到google的官方仓库下载镜像、二进制文件,这个就需要你的服务器可以上外面的网,想上外网也需要修改一些配置。

# 定制化配置文件
# 1. 节点组织配置(这里可以调整每个节点的角色)
$ vi inventory/mycluster/hosts.yaml
# 2. containerd配置(教程使用containerd作为容器引擎)
$ vi inventory/mycluster/group_vars/all/containerd.yml
# 3. 全局配置(可以在这配置http(s)代理实现外网访问)
$ vi inventory/mycluster/group_vars/all/all.yml
# 4. k8s集群配置(包括设置容器运行时、svc网段、pod网段等)
$ vi inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml
# 5. 修改etcd部署类型为host(默认是docker)
$ vi ./inventory/mycluster/group_vars/etcd.yml
# 6. 附加组件(ingress、dashboard等)
$ vi ./inventory/mycluster/group_vars/k8s-cluster/addons.yml

一键部署

# -vvvv会打印最详细的日志信息,建议开启
$ ansible-playbook -i inventory/mycluster/hosts.yaml  -b cluster.yml -vvvv

验证结果

[root@node1 ~]# kubectl get node
NAME    STATUS   ROLES           AGE    VERSION
node1   Ready    control-plane   148m   v1.25.6
node2   Ready    control-plane   127m   v1.25.6
node3   Ready    <none>          126m   v1.25.6
[root@node1 ~]# kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME                 STATUS    MESSAGE                         ERROR
etcd-2               Healthy   {"health":"true","reason":""}   
scheduler            Healthy   ok                              
controller-manager   Healthy   ok                              
etcd-1               Healthy   {"health":"true","reason":""}   
etcd-0               Healthy   {"health":"true","reason":""}   
[root@node1 ~]# kubectl get po -A
NAMESPACE     NAME                                       READY   STATUS    RESTARTS       AGE
kube-system   calico-kube-controllers-856b65b4c6-grhcz   1/1     Running   0              124m
kube-system   calico-node-h5zck                          1/1     Running   0              125m
kube-system   calico-node-r64x9                          1/1     Running   0              125m
kube-system   calico-node-z5kqt                          1/1     Running   0              125m
kube-system   coredns-9ffd646b7-2bzlf                    1/1     Running   0              124m
kube-system   coredns-9ffd646b7-vcpjr                    1/1     Running   0              124m
kube-system   dns-autoscaler-d9847d776-tbbpx             1/1     Running   0              124m
kube-system   kube-apiserver-node1                       1/1     Running   1              148m
kube-system   kube-apiserver-node2                       1/1     Running   0              127m
kube-system   kube-controller-manager-node1              1/1     Running   1              148m
kube-system   kube-controller-manager-node2              1/1     Running   1              127m
kube-system   kube-proxy-4bhlm                           1/1     Running   0              126m
kube-system   kube-proxy-5pllk                           1/1     Running   0              126m
kube-system   kube-proxy-tlrdr                           1/1     Running   0              126m
kube-system   kube-scheduler-node1                       1/1     Running   1              148m
kube-system   kube-scheduler-node2                       1/1     Running   1              127m
kube-system   nginx-proxy-node3                          1/1     Running   0              125m
kube-system   nodelocaldns-f6r8f                         1/1     Running   0              124m
kube-system   nodelocaldns-prvkh                         1/1     Running   1 (123m ago)   124m
kube-system   nodelocaldns-vm549                         1/1     Running   0              124m
[root@node1 ~]# 

集群冒烟测试

创建nginx-ds

写入配置

[root@node1 ~]# cat > nginx-ds.yml <<EOF
> apiVersion: v1
> kind: Service
> metadata:
>   name: nginx-ds
>   labels:
>     app: nginx-ds
> spec:
>   type: NodePort
>   selector:
>     app: nginx-ds
>   ports:
>   - name: http
>     port: 80
>     targetPort: 80
> ---
> apiVersion: apps/v1
> kind: DaemonSet
> metadata:
>   name: nginx-ds
> spec:
>   selector:
>     matchLabels:
>       app: nginx-ds
>   template:
>     metadata:
>       labels:
>         app: nginx-ds
>     spec:
>       containers:
>       - name: my-nginx
>         image: docker.io/library/nginx:latest
>         ports:
>         - containerPort: 80
> EOF

创建ds

[root@node1 ~]# kubectl apply -f nginx-ds.yml
service/nginx-ds created
daemonset.apps/nginx-ds created

检查IP联通性

检查各Node上Pod IP连通性

[root@node1 ~]# kubectl get pod -o wide
NAME             READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
nginx-ds-7psqb   1/1     Running   0          4m31s   10.233.75.6      node2   <none>           <none>
nginx-ds-nddxd   1/1     Running   0          4m31s   10.233.71.6      node3   <none>           <none>
nginx-ds-x9jzf   1/1     Running   0          4m31s   10.233.102.135   node1   <none>           <none>

在每个节点上ping pod ip

[root@node1 ~]# ping 10.233.75.6
PING 10.233.75.6 (10.233.75.6) 56(84) bytes of data.
64 bytes from 10.233.75.6: icmp_seq=1 ttl=63 time=1.09 ms
64 bytes from 10.233.75.6: icmp_seq=2 ttl=63 time=0.959 ms
^C
--- 10.233.75.6 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.959/1.026/1.094/0.074 ms
[root@node1 ~]# ping 10.233.71.6
PING 10.233.71.6 (10.233.71.6) 56(84) bytes of data.
64 bytes from 10.233.71.6: icmp_seq=1 ttl=63 time=4.58 ms
64 bytes from 10.233.71.6: icmp_seq=2 ttl=63 time=0.612 ms
^C
--- 10.233.71.6 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.612/2.598/4.584/1.986 ms
[root@node1 ~]# ping 10.233.102.135
PING 10.233.102.135 (10.233.102.135) 56(84) bytes of data.
64 bytes from 10.233.102.135: icmp_seq=1 ttl=64 time=1.49 ms
64 bytes from 10.233.102.135: icmp_seq=2 ttl=64 time=0.084 ms
64 bytes from 10.233.102.135: icmp_seq=3 ttl=64 time=0.083 ms
^C
--- 10.233.102.135 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.083/0.553/1.492/0.663 ms

检查service可达性

[root@node1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.233.0.1      <none>        443/TCP        5h24m
nginx-ds     NodePort    10.233.56.115   <none>        80:32177/TCP   5m46s

# 在每个节点上访问服务
[root@node1 ~]# curl 10.233.56.115:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@node1 ~]# curl 10.233.75.6:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

检查dns可用性

创建一个nginx pod

[root@node1 ~]# cat > pod-nginx.yaml <<EOF
> apiVersion: v1
> kind: Pod
> metadata:
>   name: nginx
> spec:
>   containers:
>   - name: nginx
>     image: docker.io/library/nginx:1.19
>     ports:
>     - containerPort: 80
> EOF

创建pod

[root@node1 ~]# kubectl apply -f pod-nginx.yaml
pod/nginx created

进入pod,查看dns

[root@node1 ~]# kubectl exec -it nginx -- sh
# 查看dns配置
/ # cat /etc/resolv.conf 
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 169.254.25.10
options ndots:5
# ping nginx-ds
/ # ping nginx-ds
PING nginx-ds (10.233.56.115): 56 data bytes
64 bytes from 10.233.56.115: seq=0 ttl=64 time=1.421 ms
64 bytes from 10.233.56.115: seq=1 ttl=64 time=0.121 ms
64 bytes from 10.233.56.115: seq=2 ttl=64 time=0.192 ms

日志功能

使用kubectl查看pod的容器日志

[root@node1 ~]# kubectl get pods -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
nginx            1/1     Running   0          12m   10.233.71.7      node3   <none>           <none>
nginx-ds-7psqb   1/1     Running   0          27m   10.233.75.6      node2   <none>           <none>
nginx-ds-nddxd   1/1     Running   0          27m   10.233.71.6      node3   <none>           <none>
nginx-ds-x9jzf   1/1     Running   0          27m   10.233.102.135   node1   <none>           <none>
[root@node1 ~]# kubectl logs nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/02/03 09:13:17 [notice] 1#1: using the "epoll" event method
2023/02/03 09:13:17 [notice] 1#1: nginx/1.23.2
2023/02/03 09:13:17 [notice] 1#1: built by gcc 11.2.1 20220219 (Alpine 11.2.1_git20220219) 
2023/02/03 09:13:17 [notice] 1#1: OS: Linux 4.18.0-448.el8.x86_64
2023/02/03 09:13:17 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 65535:65535
2023/02/03 09:13:17 [notice] 1#1: start worker processes
2023/02/03 09:13:17 [notice] 1#1: start worker process 30
2023/02/03 09:13:17 [notice] 1#1: start worker process 31

Exec功能

[root@node1 ~]# kubectl get pods -l app=nginx-ds
NAME             READY   STATUS    RESTARTS   AGE
nginx-ds-7psqb   1/1     Running   0          29m
nginx-ds-nddxd   1/1     Running   0          29m
nginx-ds-x9jzf   1/1     Running   0          29m
[root@node1 ~]# kubectl exec -it nginx-ds-x9jzf -- nginx -v
nginx version: nginx/1.23.2