文章

K8S 安装部署 (Ubuntu 22.04)

K8S 安装部署 (Ubuntu 22.04)

关于在 Ubuntu 22.04 环境下部署 k8s 的详细记录

环境

WireGuard PVE Openwrt 组网 Note 中记录了两台 PVE 之间的网络情况。 现在继续在这个环境下搭建 k8s,准备使用 ubuntu-01 作为 master 节点(部署 control-plane),其余两个节点作为 worker 即可。

nodeipresourceroleversion
ubuntu-01172.16.1.1014 core 30 GBmaster22.04
ubuntu-02172.16.1.1024 core 30 GBworker22.04
ubuntu-03172.16.1.1033 core 12 GBworker22.04

真希望哪天公司能淘汰一个戴尔服务器廉价卖给我 😭

准备

接下来的工作,在所有的节点上执行,可以使用 iTerm2 多窗口 broadcast 输入

主机名解析

修改 /etc/hosts 增加主机名解析记录

1
2
3
172.16.1.101    ubuntu-01
172.16.1.102    ubuntu-02
172.16.1.103    ubuntu-03

禁用 swap 空间

修改 /etc/fstab 将 swap 这一行给注释掉

1
2
3
4
5
6
7
8
9
10
11
12
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda3 during installation
UUID=8afcc49f-6158-4985-a108-69b2dd7cd55b /               ext4    errors=remount-ro 0       1
# /boot/efi was on /dev/sda2 during installation
UUID=0CE6-58A6  /boot/efi       vfat    umask=0077      0       1
#/swapfile                                 none            swap    sw              0       0

禁止休眠

1
systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target

禁止防火墙

1
2
ufw disable
ufw status

允许 iptables 检查桥接流量

1
2
modprobe overlay
modprobe br_netfilter

修改配置文件 /etc/modules-load.d/k8s.conf

1
2
overlay
br_netfilter

修改配置文件 /etc/sysctl.d/k8s.conf

1
2
3
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1

使上述配置生效

1
sysctl --system

配置 containerd

先看下系统是否有 containerd 服务

1
systemctl status containerd

没有的话需要先安装并保持开机启动,我是在 DockerHub 按照官方教程安装 Docker 后就会有 containerd 服务。

生成 containerd 的默认配置

1
containerd config default > /etc/containerd/config.toml

将默认配置作出如下修改

  • 开启 SystemdCgroup
1
SystemdCgroup = true
  • 修改 sandbox_image 镜像为阿里云 google_containers 镜像源
1
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"
  • [plugins."io.containerd.grpc.v1.cri".registry] 配置项下面增加一行 config_path
1
2
[plugins."io.containerd.grpc.v1.cri".registry]
      config_path = "/etc/containerd/certs.d"
  • 确认下面配置项已经清空
1
2
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
#      <make-sure-here-is-nothing>

配置完毕后可以重启 containerd 服务

1
systemctl restart containerd

安装 kubelet kubeadm kubectl

下述安装流程与 k8s 官方手册保持一致,此次安装的版本是 v1.30.1。

1
2
3
4
5
6
7
8
9
10
11
12
apt-get update
# apt-transport-https 可能是一个虚拟包(dummy package);如果是的话,你可以跳过安装这个包
apt-get install -y apt-transport-https ca-certificates curl gpg
# 如果 `/etc/apt/keyrings` 目录不存在,则应在 curl 命令之前创建它,请阅读下面的注释。
# sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 此操作会覆盖 /etc/apt/sources.list.d/kubernetes.list 中现存的所有配置。
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubelet kubeadm kubectl
# 锁定版本
apt-mark hold kubelet kubeadm kubectl

nginx + keepalived 高可用配置

nginx

创建 nginx 配置文件

1
vim volumes/conf/nginx.conf
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

# 使用默认配置
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

# stream 模块负责创建 TCP 和 UDP 流量代理
stream {
    log_format  main  '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
    access_log  /var/log/nginx/k8s-access.log  main;
    error_log /var/log/nginx/k8s-error.log debug;

    # upstream 定义了一个上游服务器组, 用于负载均衡
    upstream k8s-apiserver {
       server 172.16.1.101:6443;
       server 172.16.1.102:6443;
       server 172.16.1.103:6443;
    }
    server {
       listen 6443;
       # proxy_pass 会指定流量转发的目标, 即上游服务器组 k8s-apiserver
       proxy_pass k8s-apiserver;
    }
}

创建 nginx docker compose 文件

1
2
3
4
5
6
7
8
9
10
11
services:
  nginx:
    container_name: nginx-1
    image: nginx:latest
    network_mode: host
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/conf/nginx.conf:/etc/nginx/nginx.conf
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/html:/usr/share/nginx/html
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/logs:/var/log/nginx
    restart: always

keepalived

通过 apt 安装

1
apt-get install keepalived

创建配置文件 /etc/keepalived/keepalived.conf

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
global_defs {
   router_id keepalived_1    # 用于标识 keepalived 唯一实例, 主从需要区分
   vrrp_skip_check_adv_addr  # 跳过对 VRRP 广告报文来源地址的检查
   # vrrp_strict             # 启用严格的 VRRP 检查。确保收到的报文符合严格的 VRRP 协议标准, 单播模式需要注释
   vrrp_garp_interval 0.1      # 设置 GARP(Gratuitous ARP)报文的发送间隔,单位为秒。GARP 用于向网络中的其他设备通告 IP 地址的变化。设网络拓扑越复杂设置的越短
   vrrp_gna_interval 0.1       # 设置 GNA(Gratuitous NA, 针对 IPv6)报文的发送间隔,单位为秒。类似于 GARP,但用于 IPv6。网络越稳定设置的越长
   max_auto_priority         # 根据系统资源和配置自动计算 VRRP 实例的最大优先级, 一定程度可以优化性能
}

vrrp_instance VI_1 {         # 用于定义一个 VRRP 实例, 每个实例表示一组参与 VRRP 协议的路由器, 共同管理一个或多个虚拟 IP 地址
    state MASTER             # 定义当前节点的初始状态, 可以是 MASTER 和 BACKUP
    interface enp6s18        # 指定 VRRP 运行的网络接口(物理)按需修改
    virtual_router_id 11     # 定义虚拟路由器的 ID, 用于标识一个 VRRP 群组, 在同一个广播域中, 参与同一个 VRRP 实例的所有路由器都需要使用相同的 ID
    priority 100             # MASTER 设置的高一些
    advert_int 1             # 设置 VRRP 广告报文的发送间隔, 单位 s
    authentication {         # VRRP 的认证信息
        auth_type PASS       # 认证类型为简单密码(PASS)
        auth_pass 1234       # 定义用于认证的密码
    }
    nopreempt                # 当本节点成为 MASTER 时, 如果有更高优先级的节点上限, 本节点将继续保持 MASTER 的角色, 非抢占
    unicast_src_ip 172.16.1.101  # 本机IP
    unicast_peer {
        172.16.1.102
        172.16.1.103
    }
    virtual_ipaddress {
        172.16.1.100         #定义虚拟 IP 地址, 要保持和实际IP在同一网段
    }
}

配置其它节点上的 keepalived 时, 需要修改 router_id, state 以及 priority. 另外 docker compose 配置文件可以修改 container 名称.

keepalived 应该直接在本地部署, 使用 docker 部署会有一些网络问题

配置 master 节点

只需要在 ubuntu-01 执行即可

配置 master 节点之前,可以在 ubuntu-01 预先下载镜像,k8s 下载的镜像和 docker pull 不是一回事。

1
kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers

使用 kubeadm init 进行 master 节点初始化

1
2
3
4
5
6
7
kubeadm init \
  --apiserver-advertise-address=172.16.1.101 \
  --control-plane-endpoint=172.16.1.100 \
  --image-repository registry.aliyuncs.com/google_containers \
  --kubernetes-version v1.30.1 \
  --service-cidr=10.96.0.0/16 \
  --pod-network-cidr=10.244.0.0/16

其中:

  • apiserver-advertise-address 指定了 k8s api server 对外广播的 ip 地址,设置为当前 ip 地址,以便别的节点可以通过该地址访问 api server
  • service-cidr 指定了 k8s 服务的虚拟 ip 地址范围,不应该与物理网络冲突。
  • pod-network-cidr 是 pod 之间通讯的地址范围。下面要安装的 flannel 文件中就有这个网段。

下面是上述命令的输出结果

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
Your Kubernetes control-plane 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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

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 control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

  kubeadm join 172.16.3.100:6443 --token 20n67u.psrogtp3tpeqkhla \
	--discovery-token-ca-cert-hash sha256:d7273510fe2ccb40e0f2232df7c418c892e636cf7a75e0676b21cf634be1df83 \
	--control-plane

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 172.16.3.100:6443 --token 20n67u.psrogtp3tpeqkhla \
	--discovery-token-ca-cert-hash sha256:d7273510fe2ccb40e0f2232df7c418c892e636cf7a75e0676b21cf634be1df83

根据提示的配置保存集群访问认证的配置文件 这样就可以通过配置文件来访问 k8s 集群了

init 成功之后需要先在 master 节点安装一下 flannel 网络插件,使用默认值即可,不需要更新文件。

1
2
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f kube-flannel.yml

如果需要创建多 master 节点支持高可用, 可以在别的 master 节点上执行下述命令加入集群,请注意要包含 --control_plane--certificate-key 两个参数,刚刚在 master-1 执行的 kubeadm init 命令并没有输出 --certificate-key 的值,可以使用下述语句在 master-1 上生成 certificate key

1
2
3
4
❯ kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
c821cc6829e1e402e965f06aa4994fbb59a5f227f021e88daba482538c4b0fcc

然后在 master-2 节点上执行下述命令加入 master 组

1
2
3
kubeadm join 172.16.1.100:6443 --token mrik2v.i6skqyc3zs89zkqd \
        --discovery-token-ca-cert-hash sha256:6d51a002a7abdeeaff04ba988ba8271038a256809543713dca28d216c8832d15 \
        --certificate-key 58b5069121358f791d0d14f97c391cd16b6337a3953289c7baccd1f0fe23ee41  --control-plane

加入成功后会出现下述提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
This node has joined the cluster and a new control plane instance was created:

* Certificate signing request was sent to apiserver and approval was received.
* The Kubelet was informed of the new secure connection details.
* Control plane label and taint were applied to the new node.
* The Kubernetes control plane instances scaled up.
* A new etcd member was added to the local/stacked etcd cluster.

To start administering your cluster from this node, 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

Run 'kubectl get nodes' to see this node join the cluster.

执行下述命令是以 worker 身份加入 worker 加入的时候不能写 –certificate-key,这个参数是给 master 用的

1
2
kubeadm join 172.16.1.100:6443 --token mrik2v.i6skqyc3zs89zkqd \
        --discovery-token-ca-cert-hash sha256:6d51a002a7abdeeaff04ba988ba8271038a256809543713dca28d216c8832d15

加入成功后会出现下述提示

1
2
3
4
5
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

配置 worker 节点

ubuntu-01 配置完之后,应该会输出类似于 kubeadm join <ip>:<port> --token xxx --discovery-token-ca-cert-hash xxx 的命令,如果忘记了,也可以在 ubuntu-01 重新显示:

1
kubeadm token create --print-join-command

将 master 节点的 /etc/kubernetes/admin.conf 配置文件拷贝到每个 worker,保持与 master 一致即可。

kubeadm join 输出的命令在 ubuntu-02 和 ubuntu-03 上执行一遍,这样 ubuntu-02 和 ubuntu-03 就会作为 worker 加入 ubuntu-01 集群。

将 ubuntu-02 和 ubuntu-03 作为 worker 加入之后,默认 ROLE 是空的,可以手动给它们加上 ROLE 字段,下面是修改 ROLES 字段的命令:

1
2
kubectl label node ubuntu-02 node-role.kubernetes.io/worker=worker
kubectl label node ubuntu-03 node-role.kubernetes.io/worker=worker

查看当前集群所有的 node:

1
2
3
4
5
❯ kubectl get nodes -o wide -A
NAME        STATUS   ROLES           AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
ubuntu-01   Ready    control-plane   22h   v1.30.1   172.16.1.101   <none>        Ubuntu 22.04.4 LTS   6.5.0-35-generic   containerd://1.6.32
ubuntu-02   Ready    worker          22h   v1.30.1   172.16.1.102   <none>        Ubuntu 22.04.4 LTS   6.5.0-35-generic   containerd://1.6.32
ubuntu-03   Ready    worker          22h   v1.30.1   172.16.1.103   <none>        Ubuntu 22.04.4 LTS   6.5.0-35-generic   containerd://1.6.32

至此 k8s 集群创建完毕,结合之前的组网教程,可以远程在 Mac 上访问家庭内的 k8s 集群了,当然,Mac 上复制该集群的访问配置文件是必不可少的🌵。

本文由作者按照 CC BY 4.0 进行授权