在中国大陆本地部署 Kubernetes 集群
适用于 Kubernetes 1.12
基于众所周知的原因,在中国大陆是无法访问 k8s.gcr.io
。这意味着我们不能直接按照官方教程创建集群。
接下来我将演示在不借助 VPN 等资源的前提下,如何使用 kubeadm
在本地搭建一个 Single Master 集群。
本文大纲
安装
以下基于 Ubuntu 16.04 为例,安装 docker-ce, kubeadm kubelet kubectl
程序包。
这里使用阿里云镜像站的 APT 源,YUM 源的信息请参考该网站的说明。
安装 kubeadm kubelet kubectl
apt-get update && apt-get install -y apt-transport-https ca-certificates curl
curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet=1.12.5-00 kubeadm=1.12.5-00 kubectl=1.12.5-00
apt-mark hold kubelet kubeadm kubectl
安装并配置 docker-ce
apt-get update && apt-get install -y apt-transport-https ca-certificates curl
curl -s http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/docker-ce.list
deb [arch=amd64] https://mirror.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu xenial stable
EOF
apt-get update
apt-get install -y docker-ce=18.06.2~ce~3-0~ubuntu
# 使用国内镜像
cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"registry-mirrors": ["https://registry.docker-cn.com"]
}
EOF
mkdir -p /etc/systemd/system/docker.service.d
systemctl daemon-reload
systemctl restart docker
初始化
Kubernetes 集群的初始化可以分为三个步骤
- 在 Master 上运行控制平面 (Control Plane)
- 将 Node 加入到集群中
- 安装 Pod 网络的附加组件
Master
kubeadm 1.12
使用的是 v1alpha3
API,这里的定义包含了 InitConfiguration
和 ClusterConfiguration
两部分。
apiVersion: kubeadm.k8s.io/v1alpha3
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
# 从 Aliyun Registry 拉取基础镜像
pod-infra-container-image: registry.aliyuncs.com/google_containers/pause-amd64:3.1
---
apiVersion: kubeadm.k8s.io/v1alpha3
kind: ClusterConfiguration
# 从 Aliyun Registry 拉取 Control Plane 镜像
imageRepository: registry.aliyuncs.com/google_containers
# 使用确定的 Kubernetes 版本,避免初始化时从 https://dl.k8s.io/release/stable-1.12.txt 读取
kubernetesVersion: v1.12.5
networking:
# 如使用 flannel 组件应增加如下配置
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
在 Master 上,将上述内容保存名为 init.yml
文件,运行如下命令开始初始化。kubeadm
将自动下载镜像,以 Static Pod 方式运行 Control Plane。
kubeadm init --config init.yml
初始化完成后,界面上会输出一条 kubeadm join
命令,将其记录到本地,稍后会用于 Node 加入集群。命令示例如下
kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>
访问集群
可以参照 kubeadm
初始化后输出的说明,增加使用 kubectl
访问 Kubernetes 集群所需的配置。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
这时可以使用 kubectl -n kube-system get pods
查看到已部署的 Control Plane Pod。
Node
Node 加入集群应使用如下配置,诸如 <token>
应使用前一阶段界面输出的参数值替换。
apiVersion: kubeadm.k8s.io/v1alpha3
kind: JoinConfiguration
discoveryTokenAPIServers:
- <master-ip>:<master-port>
discoveryTokenCACertHashes:
- sha256:<hash>
nodeRegistration:
kubeletExtraArgs:
pod-infra-container-image: registry.aliyuncs.com/google_containers/pause-amd64:3.1
token: <token>
在 Node 上,将上述内容保存名为 join.yml
的文件,运行如下命令加入集群。
kubeadm join --config join.yml
运行成功后,我们可以在 Master 上使用 kubectl get nodes
查看到已加入集群的 Node。
Pod Network
在完成前面两步后,通过 kubectl get nodes
我们可以看到 Master 和 Node 状态是 NotReady
,这是因为缺少 Pod Network 附加组件。
现在部署的 Pod 不会被分配 IP,会维持在 ContainerCreating
状态。比如通过 kubectl -n kube-system get pods -l k8s-app=kube-dns
查看到的 CoreDNS Pod。
可以选择任意一款支持 CNI 的网络组件,这里使用 flannel
作为示例,在 Master 上运行如下命令。
# 内容拷贝自 https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 只是从 Aliyun Registry 加载 flannel 镜像
kubectl apply -f https://git.io/fxNfD
待网络组件安装完成后,再次运行 kubectl -n kube-system get pods -l k8s-app=kube-dns
可以看到 CoreDNS Pod 已经变为 Running
状态。
测试
在全部初始化完成后,我们可以做一些测试,确保各个功能模块都是正确运行的。
验证 kube-apiserver, kube-controller-manager, kube-scheduler, pod network
正常
# 部署一个 Nginx Deployment,包含两个 Pod
# https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
kubectl create deployment nginx --image=nginx:alpine
kubectl scale deployment nginx --replicas=2
# 待启动后,两个 Nginx Pod 应该是 Running 状态,并且各自分配有 10.244 开头的集群内 IP
kubectl get pods -l app=nginx -o wide
# 结果示例
# NAME READY STATUS RESTARTS AGE IP NODE
# nginx-65d5c4f7cc-d88nq 1/1 Running 0 3s 10.244.1.7 izuf6ex1vq9wpui8cgkiekz
# nginx-65d5c4f7cc-q8vlq 1/1 Running 0 3s 10.244.2.3 izuf6efhmsjefx1lfbu3qaz
验证 kube-proxy
正常
# 以 NodePort 方式对外提供服务
# https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/
kubectl expose deployment nginx --port=80 --type=NodePort
# Nginx 服务应该得到一个 10.96 开头的集群内 IP,以及集群外可访问的 Port
kubectl get services nginx
# 结果示例
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx NodePort 10.98.222.155 <none> 80:32630/TCP 14s
# 可以通过任意 NodeIP:Port 在集群外部访问这个服务
curl http://node-ip:32630
验证 dns, pod network
正常
# 启动一个 Busybox 部署,并进入其内部
# 如果没有出现提示符,按下回车键
kubectl run -it curl --image=radial/busyboxplus:curl
# 输入命令 nslookup nginx 应可以正确解析出集群内的 IP,证明 DNS 服务正常
[ root@curl-5cc7b478b6-7zxlq:/ ]$ nslookup nginx
# 结果示例
# Server: 10.96.0.10
# Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
#
# Name: nginx
# Address 1: 10.98.222.155 nginx.default.svc.cluster.local
# 输入命令 curl nginx 应可以正确返回 Nginx 首页,证明 kube-proxy 正常
[ root@curl-5cc7b478b6-7zxlq:/ ]$ curl http://nginx/
# 如果部署有多个 Node,应针对每个 Nginx Pod 的集群内 IP 进行 curl,证明跨 Node 的 Pod Network 正常
# 这里是比较容易出问题的故障点,请参考网络组件相关文档进行排查
[ root@curl-5cc7b478b6-7zxlq:/ ]$ curl http://10.244.1.7/
[ root@curl-5cc7b478b6-7zxlq:/ ]$ curl http://10.244.2.3/
结语
至此,我们搭建了一个 Kubernetes 集群,接下来可以参考官方文档部署其他服务了。
附记
本文默认从 registry.aliyuncs.com
拉取 Docker Image,该地址可在阿里云之外访问。
也可以根据自身所属区域,使用 registry.<region-id>.aliyuncs.com
来替代,比如北京区域可使用 registry.cn-beijing.aliyuncs.com
。
如果是在阿里云上 VPC 网络内搭建,可以使用 registry-vpc.<region-id>.aliyuncs.com
内网地址。