Kubernetes离线安装手册(非高可用版)

集群信息

1. 节点规划

部署k8s集群的节点按照用途可以划分为如下3类角色:

  • master :集群的master节点,至少一台
  • slave:集群的slave节点,非必须存在
  • init:集群的初始化节点,提供集群初始化必要的镜像及软件源,可以与master节点使用同一台机器

单个节点可以对应多个角色,比如master节点可以同时作为init节点。因为slave节点不是必须存在,因此部署非高可用集群最少仅需一台机器即可,基础配置不低于2C4G。

本例为了演示slave节点的添加,会部署一台master+1台slave,其中master和init共用一台机器,节点规划如下:

主机名 节点ip 角色 部署组件
k8s-init 10.0.129.84 init registry, httpd
k8s-slave 10.0.128.240 slave kubectl, kubeadm, kubelet, kube-proxy, flannel
k8s-master 10.0.129.84 master etcd, kube-apiserver, kube-controller-manager, kubectl, kubeadm, kubelet, kube-proxy, flannel

2. 组件版本

组件 版本 说明
CentOS 7.5.1804
Kernel Linux 3.10.0-862.el7.x86_64
etcd 3.2.24 使用容器方式部署,默认数据挂载到本地路径
coredns 1.2.6
kubeadm v1.13.3
kubectl v1.13.3
kubelet v1.13.3
kube-proxy v1.13.3
flannel v0.11.0 使用vxlan作为backend
httpd v2.4.6 部署在init节点,默认使用80端口提供服务
registry v2.3.1 部署在init节点,默认使用60080端口提供服务

安装前准备工作

1. 设置hosts解析

操作节点:所有节点(k8s-init,k8s-master,k8s-slave)均需执行 - 修改hostname hostname必须只能包含小写字母、数字、",“、”-“,且开头结尾必须是小写字母或数字

# 在master节点
$ hostnamectl set-hostname k8s-master #设置master节点的hostname

# 在slave节点
$ hostnamectl set-hostname k8s-slave #设置slave节点的hostname
  • 添加hosts解析
$ cat >>/etc/hosts<<EOF
10.0.129.84 k8s-master k8s-init
10.0.128.240 k8s-slave
EOF

2. 调整系统配置

操作节点: 所有的master和slave节点(k8s-master,k8s-slave)需要执行

本章下述操作均以k8s-master为例,其他节点均是相同的操作(ip和hostname的值换成对应机器的真实值)

  • 设置安全组开放端口 如果节点间无安全组限制(内网机器间可以任意访问),可以忽略,否则,至少保证如下端口可通: k8s-init节点:TCP:7443,60080,60081,UDP协议端口全部打开 k8s-master节点:TCP:6443,2379,2380,UDP协议端口全部打开

  • 设置iptables

$  iptables -P FORWARD ACCEPT
  • 关闭swap
$ swapoff -a
# 防止开机自动挂载 swap 分区
$  sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
  • 关闭selinux和防火墙
$ sed -ri 's#(SELINUX=).*#\1disabled#' /etc/selinux/config
$ setenforce 0
$ systemctl disable firewalld && systemctl stop firewalld
  • 修改内核参数
$ cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
EOF
$ modprobe br_netfilter
$ sysctl -p /etc/sysctl.d/k8s.conf
  • 加载ipvs模块
$ 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 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4

3. 拷贝安装包

操作节点: k8s-init节点

# 安装包拷贝到k8s-init节点的/opt目录
$ scp k8s-installer.tar.gz root@k8s-init:/opt 
# 解压并查看安装包
$ tar -zxf /opt/k8s-installer.tar.gz -C /opt
$ ls -lh /opt/k8s-installer  # 查看安装包,会包含如下4项
total 337M
drwxr-xr-x 3 root root 4.0K Jun 16 21:00 docker-ce
-rw-r--r-- 1 root root  13K Jun 16 14:00 kube-flannel.yml
drwxr-xr-x 3 root root 4.0K Jun 15 15:19 registry
-rw------- 1 root root 337M Jun 16 10:24 registry-image.tar

4. 部署yum仓库

操作节点: k8s-init

  • 配置本地repo文件
$ cat <<EOF > /etc/yum.repos.d/local.repo
[local]
name=local
baseurl=file:///opt/k8s-installer/docker-ce
gpgcheck=0
enabled=1
EOF
$ yum clean all && yum makecache
  • 安装并配置httpd服务
$ yum install -y  httpd --disablerepo=*  --enablerepo=local

httpd默认使用80端口,为避免端口冲突,默认修改为60081端口

$ sed -i 's/Listen 80/Listen 60081/g' /etc/httpd/conf/httpd.conf

将安装包拷贝到服务目录中,服务目录默认使用/var/www/html

$ cp -r /opt/k8s-installer/docker-ce/ /var/www/html/
$ systemctl enable httpd && systemctl start httpd

5. 安装并配置docker

操作节点: 所有节点(k8s-init,k8s-master,k8s-slave)均需执行 - 配置yum repo 其中60081端口若有修改,需要替换为httpd实际使用的端口

$ cat <<EOF > /etc/yum.repos.d/local-http.repo
[local-http]
name=local-http
baseurl=http://10.0.129.84:60081/docker-ce
gpgcheck=0
enabled=1
EOF
$ yum clean all && yum makecache
  • 配置docker daemon文件 其中60080端口为镜像仓库的端口,如使用其他端口,需在下章节中替换为实际使用的端口
$ mkdir /etc/docker
$ cat <<EOF > /etc/docker/daemon.json
{
    "insecure-registries": [
        "10.0.129.84:60080"
    ],
    "storage-driver": "overlay2"
}
EOF
  • 安装并启动docker
$ yum install -y docker-ce docker-ce-cli containerd.io  --disablerepo=*  --enablerepo=local-http
$ systemctl enable docker && systemctl start docker

6. 配置镜像仓库

该仓库存储k8s部署所需的kube-apiserverkube-controller-managerkube-scheduleretcdflannelcoredns等组件的镜像,使用docker run的方式部署,默认暴漏机器的60080端口提供服务。

操作节点: 只在k8s-init节点执行 - 加载镜像到本地

$ docker load -i /opt/k8s-installer/registry-image.tar
$ docker images # 查看加载成功的registry镜像 
REPOSITORY                               TAG                 IMAGE ID            CREATED             SIZE
index.alauda.cn/alaudaorg/distribution   latest              2aee66f2203d        2 years ago         347MB
  • 启动registry镜像仓库 默认使用60080作为registry对外的服务端口,如需修改,需将各节点的/etc/docker/daemon.json中的insecure-registries中配置的端口一并改掉
$ docker run -d --restart=always --name pkg-registry -p 60080:5000 -v /opt/k8s-installer/registry/:/var/lib/registry index.alauda.cn/alaudaorg/distribution:latest

部署kubernetes

1. 安装 kubeadm, kubelet 和 kubectl

操作节点: 所有的master和slave节点(k8s-master,k8s-slave) 需要执行

$ yum install -y  kubeadm kubectl kubelet --disablerepo=*  --enablerepo=local-http

2. 配置kubelet

操作节点: 所有的master和slave节点(k8s-master,k8s-slave) 需要执行 - 设置kubelet开机启动

$ systemctl enable kubelet
  • 配置kubelet 配置文件/etc/systemd/system/kubelet.service,注意需要将–pod-infra-container-image地址设置为实际的镜像仓库地址(默认是k8s-init机器ip:60080)
$ cat <<EOF > /etc/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/

[Service]
Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true"
Environment="KUBELET_INFRA_CONTAINER_IMAGE=--pod-infra-container-image=10.0.129.84:60080/k8s/pause:3.1"
ExecStart=/usr/bin/kubelet $KUBELET_SYSTEM_PODS_ARGS $KUBELET_INFRA_CONTAINER_IMAGE
Restart=always
StartLimitInterval=0
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

3. 配置kubeadm初始化文件

操作节点:只在master节点(k8s-master)执行 需要修改如下两处: - advertiseAddress:修改为k8s-master的内网ip地址 - imageRepository:修改为k8s-init的内网ip地址

$ cat <<EOF > /opt/kubeadm.conf
apiVersion: kubeadm.k8s.io/v1beta1
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 10.0.129.84
  bindPort: 6443
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta1
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: ""
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: 10.0.129.84:60080/k8s
kind: ClusterConfiguration
kubernetesVersion: v1.13.3
networking:
  dnsDomain: cluster.local
  podSubnet: "10.244.0.0/16"
  serviceSubnet: 10.96.0.0/12
scheduler: {}
EOF

4. 提前下载镜像

操作节点:只在master节点(k8s-master)执行

# 查看需要使用的镜像列表,若无问题,将得到如下列表
$ kubeadm config images list --config /opt/kubeadm.conf
10.0.129.84:60080/k8s/kube-apiserver:v1.13.3
10.0.129.84:60080/k8s/kube-controller-manager:v1.13.3
10.0.129.84:60080/k8s/kube-scheduler:v1.13.3
10.0.129.84:60080/k8s/kube-proxy:v1.13.3
10.0.129.84:60080/k8s/pause:3.1
10.0.129.84:60080/k8s/etcd:3.2.24
10.0.129.84:60080/k8s/coredns:1.2.6
  # 提前下载镜像到本地
$ kubeadm config images pull --config /opt/kubeadm.conf

5. 初始化master节点

操作节点:只在master节点(k8s-master)执行

kubeadm init --config /opt/kubeadm.conf

若初始化成功后,最后会提示如下信息:

...
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 10.0.129.84:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:6bb7e2646f1f846efddf2525c012505b76831ff9453329d0203d010814783a51

接下来按照上述提示信息操作,配置kubectl客户端的认证

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

此时使用 kubectl get nodes查看节点应该处于notReady状态,因为还未配置网络插件

6. 添加slave节点到集群中

操作节点:所有的slave节点(k8s-slave)需要执行 在每台slave节点,执行如下命令,该命令是在kubeadm init成功后提示信息中打印出来的,需要替换成实际init后打印出的命令。

$ kubeadm join 10.0.129.84:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:6bb7e2646f1f846efddf2525c012505b76831ff9453329d0203d010814783a51

7. 安装flannel插件

操作节点:只在master节点(k8s-master)执行 - 拷贝kube-flannel.yml文件 把kube-flannel.yml拷贝到master节点的/opt目录

$ cp /opt/k8s-installer/kube-flannel.yml /opt

⚠️注意:如果k8s-master和k8s-init节点不是同一台机器,需要把kube-flannel.yml从k8s-init节点远程拷贝到master节点的/opt目录 $ scp root@k8s-init:/opt/k8s-installer/kube-flannel.yml /opt

  • 替换flannel镜像地址 其中10.0.129.84:60080需要替换为实际的镜像仓库地址(k8s-init节点ip:60080)
$ sed  -i "s#quay.io/coreos#10.0.129.84:60080/k8s#g" /opt/kube-flannel.yml

若配置kubeadm初始化文件章节中,podSubnet使用了非10.244.0.0/16的值,则需要对应的修改kube-flannel.yml文件中如下部分,保持一致即可,否则会造成flannel无法启动。

125   net-conf.json: |
126     {
127       "Network": "10.244.0.0/16",
128       "Backend": {
129         "Type": "vxlan"
130       }
131     }
  • 创建flannel相关资源
$ kubectl create -f /opt/kube-flannel.yml

8. 设置master节点是否可调度(可选)

操作节点:k8s-master 默认部署成功后,master节点无法调度业务pod,如需设置master节点也可以参与pod的调度,需执行:

$ kubectl taint node k8s-master node-role.kubernetes.io/master:NoSchedule-

9. 验证集群

操作节点: 在master节点(k8s-master)执行

$ kubectl get nodes  #观察集群节点是否全部Ready
NAME                STATUS   ROLES    AGE   VERSION
k8s-master   Ready    master   22h   v1.13.3
k8s-slave   Ready    <none>   22h   v1.13.3

创建测试nginx服务,需要将10.0.129.84替换为实际k8s-init节点的ip地址

$ kubectl run  test-nginx --image=10.0.129.84:60080/k8s/nginx

查看pod是否创建成功,并访问pod ip测试是否可用

$ kubectl get po -o wide |grep test-nginx
test-nginx-7d65ddddc9-lcg9z       1/1     Running            0          12s     10.244.1.3   k8s-slave    <none>           <none>
$ curl 10.244.1.3 # 验证是否服务可通
...
<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>
...