云原生实践:内网构建 Kubernetes 与 docker 环境

前言

项目组出于某种需要,拟在内网构建一套云原生环境,尝试脱离阿里提供的PAAS服务进行微服务应用的部署。

可能大家通常都是直接使用相关部门构建完成的环境,自己从没有动手构建过云原生的环境。这里给大家提供本人的实践,抛砖引玉,仅供参考。

首先,公司提供的服务器非常干净,内网属于要什么没什么的状态,一切所需的工件都需要从外网下载并通过堡垒机转移至内网,所以通过各种一键式命令部署,经由互联网拉取依赖或镜像的方案都不成立。而二进制方式又太过复杂,因此我选择 Kubeadm 来帮助我构建环境。

这里需要说明的是,Kubeadm 经过迭代,已经更加适应在生产环境的应用,当然,应视具体情况而定。

安装包和 docker 镜像准备

我在外网工作机安装了 VMware 来下载所需的资源。

所需的工件包括:

  • createrepo 用于创建内网 yum 源
  • docker (及其依赖)
  • kubeadm (及其依赖 kubectl, kubelet, kubernetes-cni, cri-tools)
  • docker images
    • coredns
    • dashboard
    • etcd
    • kube-apiserver
    • kube-controller-manager
    • kube-proxy
    • kube-scheduler
    • mirrored-flannelcni-flannel
    • mirrored-flannelcni-flannel-cni-plugin
    • pause

关于 RPM 包,增加对应的镜像源后,

yum list [name] --showduplicates                                    查看版本
yum install --downloadonly --downloaddir /path [name]-[version]     下载对应版本不安装(不会下载已拥有的依赖)

如果你的服务器允许有一台接入外网作为跳板,并且服务器已有的依赖都相同,那么仅需要上面的命令,然后使用 scp 复制到其他服务器。

但是对于完全无法访问外网的情况,在下载了 docker-ce 和 kubeadm 后,使用 repotrack 命令 进一步下载全量依赖包(需要安装 yum-utils)。

repotrack [name]           在当前文件夹下载对应的全量依赖

关于镜像,这里最好先去官网查看文档,确认版本没有冲突后,再去 docker 镜像仓库 里面下载对应版本的依赖。

在 VMware 安装 docker,下载镜像,使用 docker save 命令将其保存为 tar 包。

这里可以把 rpm 包放在一起,这样安装时只需要让 yum 自动判断依赖关系。

如果嫌麻烦,这里提供我搜集好的内网构建所需的资源。

链接:https://pan.baidu.com/s/1Rr89zi5d_W3sZeewCz8zGg 
提取码:tmlc

执行构建

createrepo 创建本地 yum 源

首先安装 createrepo。

在 /etc/yum.repos.d/ 下的 repo 文件中,增加存放本地 rpm 安装包的文件夹 localrepo

[localrepo]
name=RedFlag-Localrepo
baseurl=file:///home/localrepo/
gpgcheck=0
enabled=1

执行 createrepo /home/localrepo 创建 yum repo

服务器准备工作

systemctl stop firewalld          临时关闭防火墙,或者手动打开所需的端口
systemctl disable firewalld       长期关闭

setenforce 0                      临时关闭 SELinux,这个争议较大,大部分人选择关闭,也可以手动设置规则
/etc/selinux/config   disabled    长期关闭

swapoff -a                        临时关闭分区交换
hostnamectl set-hostname [name]   设置主机名
/etc/hosts                        添加 ip 映射

/etc/sysctl.conf                  新增 ip 规则
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-ip6table=1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-iptables=1" >> /etc/sysctl.conf

sysctl --system                   更新配置
chrony                            时间同步(内网服务器一般都做了)

安装 docker

由于配置了本地源,使用 yum 命令安装即可

systemctl start docker            启动 docker
systemctl enable docker.service   自动启动 docker
docker load -i [name].tar         导入镜像包

docker load -i coredns.tar;
docker load -i etcd.tar;
docker load -i dashboard.tar;
docker load -i kube-controller-manager.tar;
docker load -i kube-apiserver.tar;
docker load -i kube-proxy.tar;
docker load -i kube-scheduler.tar;
docker load -i pause.tar;
docker load -i metrics-scraper.tar;
docker load -i mirrored-flannelcni-flannel.tar;
docker load -i mirrored-flannelcni-flannel-cni-plugin.tar;


下面是给对应容器添加 tag,以便于 kubeadm 获取,image id 对同一个镜像是固定的

docker tag 3fc1d62d6587 k8s.gcr.io/kube-apiserver:v1.23.5;
docker tag b0c9e5e4dbb1 k8s.gcr.io/kube-controller-manager:v1.23.5;
docker tag 3c53fa8541f9 k8s.gcr.io/kube-proxy:v1.23.5;
docker tag 884d49d6d8c9 k8s.gcr.io/kube-scheduler:v1.23.5;
docker tag 68d542c34203 k8s.gcr.io/etcd:3.5.1-0;
docker tag a4ca41631cc7 k8s.gcr.io/coredns/coredns:v1.8.6;
docker tag 6270bb605e12 k8s.gcr.io/pause:3.6;
docker tag 8b675dda11bb docker.io/rancher/mirrored-flannelcni-flannel:v0.19.2;
docker tag fcecffc7ad4a docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0;
docker tag 783e2b6d87ed kubernetesui/dashboard:v2.6.1;
docker tag 115053965e86 kubernetesui/metrics-scraper:v1.0.8;

创建并修改 /etc/docker/daemon.json

{
  "exec-opts":["native.cgroupdriver=systemd"]
}

重启 docker

安装 kubernetes

这里我把 kubernetes 需要的 rpm 包放在一个文件夹里,只需要 yum install *.rpm

使用 kubeadm 启动

kubeadm config print init-defaults > kubeadm-config.yaml   保存默认 config 配置,并进行修改

这里略微修改了几处

localAPIEndpoint:
  advertiseAddress: 本机 IP

nodeRegistration:
  name:{本主机名}
  imagePullPolicy: IfNotPresent

# 内网可以不修改,切换仓库为阿里云镜像
imageRepository: registry.aliyuncs.com/google_containers

kubernetesVersion: 1.23.5

networking:
  podSubnet: 10.244.0.0/16

kubeadm init
kubeadm init --config [config file]

启动的时候还是遇到过许多问题的,通过如下命令尝试排查错误:

docker ps -a                  查看容器状态
journalctl -u kubelet         查看错误日志
docker logs [container_id]    查看容器日志
/var/log/containers or pods   进入如下地址查看日志

我遇到的问题是,关闭 SELinux 后依然报 permission denied。查看日志后发现 kubeadm 创建的 PKI 文件夹下的文件无法被读取。

那么我们在后台执行 kubeadm init 命令,并手动进入 /etc/kubernetes/ 使用 chmod 755 -R 给 pki 文件夹赋予权限,即解决问题。

启动 flannel 和 dashboard

dashboard 的配置文件修改(增加 NodePort)

recommended.yaml 文件直接去官网复制:

https://github.com/kubernetes/dashboard/blob/v2.6.1/aio/deploy/recommended.yaml


--- 

kind: Service

...

spec:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30118
  selector:
    k8s-app: kubernetes-dashboard
scp /etc/kubernetes/admin.conf root@ip:/etc/kubernetes/    使用 scp 命令复制 admin.conf 文件到其他服务器
export KUBECONFIG=/etc/kubernetes/admin.conf               系统环境中增加文件路径
# 这里更建议在 /etc/profile 里新增这一行,并 source

master: kubeadm token create --print-join-command          创建 token

node 节点执行 join command

master: kubectl apply -f kube-flannel.yml                  启动 flannel
master: kubectl apply -f recommended.yml                   启动 dashboard(配置文件中 imagePullPolicy 应为 IfNotPresent)
master: kubectl apply -f dashboard-admin.yml           配置 dashboard 用户

kubectl -n kube-system describe $(kubectl -n kube-system get secret -n kube-system -o name | grep namespace) | grep token
                                                           获取 dashboard 访问令牌

开启 IPVS

ipvsadm -Ln

yum install ipset ipvsadm -y

cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
 
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF

chmod +x /etc/sysconfig/modules/ipvs.modules

/bin/bash /etc/sysconfig/modules/ipvs.modules

# 查看
lsmod | grep -e ip_vs -e nf_conntrack_ipv4

kubectl edit cm kube-proxy -n kube-system
# 修改 mode 为 "ipvs"
# 修改 masqueradeAll 为 true


# 删除 pod 自动拉起新的

# 检查 ipvs
ipvsadm -Ln

安装 Metrics-server 监控节点资源

# 下载配置文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

vim components.yaml
# ./找到 containers
# 在 args 下新增参数
-- -kubelet-insecure-tls

# 替换镜像地址
sed -i 's/k8s.gcr.io\/metrics-server/registry.cn-hangzhou.aliyuncs.com\/google_containers/g' components.yaml

安装 ingress-nginx 暴露服务

# 获取配置文件
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/cloud/deploy.yaml

# 镜像仓库替换
controller
image: bitnami/nginx-ingress-controller:1.1.2

create/patch
image: liangjw/kube-webhook-certgen:v1.1.1

其他命令

提供一些排错和其他命令

kubectl get pods --all-namespaces                   查看全部 pods
kubectl get svc,pods -n [namespace]                 查看 svc,pods 信息
kubectl logs -f [pod-name] -n [namespace]           查看 pod 日志
kubectl delete pod/[pod-name] -n [namespace]        删除 pod 后自动重启 pod
docker rm $(docker ps -all -q -f status=exited)     删除不使用的容器(慎重)
docker rmi $(docker images -f "dangling=true" -q)   删除空悬镜像

遇到 cni0 网卡错误,可以删除 cni0,系统会自动创建新的:

sudo ifconfig cni0 down
sudo ip link delete cni0

容器和外部交互操作:

// 打包镜像
docker commit [container_id] [image_name]

// 创建检测用的 busy-box
centos 进入 sh -c 'while true; do sleep 3600; done'

// 复制出 Pod
kubectl cp [namespace]/[podname]:[filePath] [filePath]

// 复制进 Pod(多个容器)
kubectl cp [src_path] [namespace]/[podname]:[filePath] -c [container_name]

// 一个容器
kubectl exec -it [podname] -n [namespace] -- /bin/sh

// 多个容器
kubectl exec -it [podname] -c [container_name] -n [namespace] -- /bin/sh