部署说明
此篇文章介绍的是Kubernets的1.10.2版本使用kubeadm 工具自动化部署一套简单的k8s集群,不涉及具体原理的说明。在后续的更新中会逐步加入一些常见的生产应用案例。
环境准备
Master: 10.0.0.1 node-1
node: 10.0.0.2 node-2
所有节点初始化
1、所有节点安装docker,官方推荐docker 1.12的版本,使用 v1.11, v1.13 和v17.03的也可以,不要使用最新的版本。
yum install -y docker-ce-selinux-17.03.2.ce-1.el7.centos.noarch.rpm
yum install -y docker-ce-17.03.2.ce-1.el7.centos.x86_64.rpm
2、配置国内镜像源:
cat < /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
3、安装所需组件
setenforce 0
yum install -y kubelet kubeadm kubectl
systemctl enable docker && systemctl start docker
systemctl enable kubelet && systemctl start kubelet
4、查看docker 使用的Cgroup driver 和 k8s的是否一致,如果不一致需要修改:
docker info | grep -i cgroup
cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf|grep "cgroup-driver"
#不一致的情况下需要修改:
sed -i "s/cgroup-driver=systemd/cgroup-driver=cgroupfs/g" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
5、修改系统配置,防止iptable报错:
cat < /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system
6、重启kubelet:
systemctl daemon-reload
systemctl restart kubelet
7、在docker 的启动文件中,加入国内的镜像加速,重启docker:
vim /usr/lib/systemd/system/docker.service
...
ExecStart=/usr/bin/dockerd --registry-mirror https://qxx96o44.mirror.aliyuncs.com
...
systemctl daemon-reload
systemctl restart docker
8、设置主机名并解析,同步系统时间。
ntpdate times.aliyun.com
安装Master
初始化Master
在此处下载docker镜像: https://hub.docker.com/r/anjia0532/
1、使用如下脚本,下载镜像,并修改为google的源,否则容器无法启动:
#!/bin/bash
images=(kube-proxy-amd64:v1.10.2 kube-scheduler-amd64:v1.10.2 kube-controller-manager-amd64:v1.10.2 kube-apiserver-amd64:v1.10.2
etcd-amd64:3.1.12 pause-amd64:3.1 kubernetes-dashboard-amd64:v1.8.3 k8s-dns-sidecar-amd64:1.14.8 k8s-dns-kube-dns-amd64:1.14.8
k8s-dns-dnsmasq-nanny-amd64:1.14.8)
for imageName in ${images[@]} ; do
docker pull anjia0532/$imageName
docker tag anjia0532/$imageName k8s.gcr.io/$imageName
docker rmi anjia0532/$imageName
done
执行此脚本,完成镜像的下载。
2、使用kubeadm init
自动安装 Master 节点,需要指定版本:
kubeadm init --kubernetes-version=v1.10.2 # 使用weave 等网络以这种方式初始化
kubeadm init --kubernetes-version=v1.10.2 --pod-network-cidr=10.244.0.0/16 # 使用flannel 网络需要加 --pod-network-cidr 参数
提示:在执行此命令的过程中,可以实时查看/var/log/message中的日志,确认服务是否启动,要特别注意镜像的版本,名称一致性问题,输出成功的记录需要保留,后面还会用到。
3、服务启动后需要根据输出提示,进行配置,如果是非root 用户需要执行:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 如果是root 用户执行的初始化,则已经创建了此文件, 只需执行:
export KUBECONFIG=/etc/kubernetes/admin.conf
配置网络
提示:我们需要安装网络插件才能使pod之间进行通信,网络插件的安装必须在应用部署之前。同时,在启动kube-dns和内部辅助服务之前必须先配置好网络。
K8S支持多种网络插件,下面是对常见几种插件的简单介绍:
- ACI通过思科ACI提供集成的集装箱网络和网络安全。
- Calico是一个安全的L3网络和网络策略提供者。
- Canal 结合Flannel和Calico,提供网络和网络策略。
- Cilium是L3网络和网络策略插件,可以透明地实施HTTP / API / L7策略。支持路由和覆盖/封装模式
- CNI-Genie使Kubernetes能够无缝地连接到一系列CNI插件,例如Calico,Canal,Flannel,Romana或Weave。
- Contiv为各种用例和丰富的策略框架提供了可配置的网络(使用BGP的本地L3,使用vxlan的覆盖,传统L2和Cisco-SDN / ACI)。 Contiv项目完全开源。安装程序提供基于kubeadm和非kubeadm的安装选项。
- Flannel 提供一种覆盖网络,可以与Kubernetes一起使用。
- Multus 提供除Kubernetes中的SRIOV,DPDK,OVS-DPDK和VPP工作负载之外,还是一个多插件,用于支持Kubernetes中的多个网络,以支持所有CNI插件(例如Calico,Cilium,Contiv,Flannel)。
- NSX-T容器插件(NCP)提供VMware NSX-T与Kubernetes等容器编排器之间的集成,以及NSX-T与基于容器的CaaS / PaaS平台(如Pivotal Container Service(PKS)和Openshift 。
- Nuage是一个SDN平台,可以在Kubernetes Pod和非Kubernetes环境之间提供基于策略的网络,并提供可视性和安全监控。
- Romana是一种用于pod网络的第3层网络解决方案,也支持NetworkPolicy API。 Kubeadm附加安装细节可在此处获得。
- Weave提供网络和网络策略,将在网络分区的两侧进行工作,并且不需要外部数据库
这里我们选择使用 flannel网络。
1、在Master上执行如下命令,完成网络安装:
sysctl net.bridge.bridge-nf-call-iptables=1
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml
## weave 网络使用如下命令,有兴趣的同学可以尝试☺
sysctl net.bridge.bridge-nf-call-iptables=1
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
2、验证是否正常启动。
[root@node-1 ~]# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system etcd-node-1 1/1 Running 0 9m
kube-system kube-apiserver-node-1 1/1 Running 0 9m
kube-system kube-controller-manager-node-1 1/1 Running 0 9m
kube-system kube-dns-86f4d74b45-jjc42 3/3 Running 0 10m
kube-system kube-flannel-ds-hfv57 1/1 Running 0 9m
kube-system kube-proxy-wsmxl 1/1 Running 0 10m
kube-system kube-scheduler-node-1 1/1 Running 0 9m
端口信息:
[root@node-1 ~]# netstat -lntpu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:10248 0.0.0.0:* LISTEN 9321/kubelet
tcp 0 0 127.0.0.1:10249 0.0.0.0:* LISTEN 9751/kube-proxy
tcp 0 0 127.0.0.1:10251 0.0.0.0:* LISTEN 9575/kube-scheduler
tcp 0 0 127.0.0.1:2379 0.0.0.0:* LISTEN 9521/etcd
tcp 0 0 127.0.0.1:10252 0.0.0.0:* LISTEN 9583/kube-controlle
tcp 0 0 127.0.0.1:2380 0.0.0.0:* LISTEN 9521/etcd
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 963/sshd
tcp6 0 0 :::10250 :::* LISTEN 9321/kubelet
tcp6 0 0 :::6443 :::* LISTEN 9590/kube-apiserver
tcp6 0 0 :::10255 :::* LISTEN 9321/kubelet
tcp6 0 0 :::10256 :::* LISTEN 9751/kube-proxy
tcp6 0 0 :::22 :::* LISTEN 963/sshd
udp 0 0 0.0.0.0:8472 0.0.0.0:* -
提示:如果执行此命令出现x509的认证失败错误,请确认当前的命令行窗口已经export admin.conf的环境变量。
故障排查思路:
- 确认端口和容器是否正常启动,查看 /var/log/message日志信息
- 通过docker logs ID 查看容器的启动日志,特别是频繁创建的容器
- 使用
kubectl --namespace=kube-system describe pod POD-NAME
查看错误状态的pod日志。 - 使用kubectl -n ${NAMESPACE} logs ${POD_NAME} -c ${CONTAINER_NAME} 查看具体错误。
- Calico - Canal - Flannel已经被官方验证过,其他的网络插件有可能有坑,能不能爬出来就看个人能力了。
- 一般常见的错误是镜像名称版本不对或者镜像无法下载。
添加节点
1、在需要添加的节点上执行:
docker pull mirrorgooglecontainers/pause-amd64:3.1
docker pull mirrorgooglecontainers/kube-proxy-amd64:v1.10.2
docker tag mirrorgooglecontainers/pause-amd64:3.1 k8s.gcr.io/pause-amd64:3.1
docker tag mirrorgooglecontainers/kube-proxy-amd64:v1.10.2 k8s.gcr.io/kube-proxy-amd64:v1.10.2
sysctl net.bridge.bridge-nf-call-iptables=1
# 此行命令来源于初始化Master成功后的输出
kubeadm join 10.0.0.1:6443 --token h00k39.t6l79i7cbm79n4gy --discovery-token-ca-cert-hash sha256:205922c8412e5a3ea1616c060c79c9b6b38d098833f46d261fdf5ed1ca7e3027
提示:如果执行join命令时提示token过期,按照提示在Master 上执行kubeadm token create 生成一个新的token。
2、执行添加命令后,在Master上查看节点信息:
[root@node-1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
node-1 Ready master 1h v1.10.2
node-2 Ready 23m v1.10.2
3、查看端口信息:
[root@node-2 ~]# netstat -lntpu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:10248 0.0.0.0:* LISTEN 24246/kubelet
tcp 0 0 127.0.0.1:10249 0.0.0.0:* LISTEN 25289/kube-proxy
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 966/sshd
tcp6 0 0 :::10250 :::* LISTEN 24246/kubelet
tcp6 0 0 :::10255 :::* LISTEN 24246/kubelet
tcp6 0 0 :::10256 :::* LISTEN 25289/kube-proxy
tcp6 0 0 :::22 :::* LISTEN 966/sshd
udp 0 0 0.0.0.0:8472 0.0.0.0:* -
4、配置node节点,查看kubete信息:
[root@node-1 ~]# scp /etc/kubernetes/admin.conf 10.0.0.2:/etc/kubernetes/
[root@node-2 ~]# kubectl --kubeconfig /etc/kubernetes/admin.conf get nodes
NAME STATUS ROLES AGE VERSION
node-1 Ready master 1h v1.10.2
node-2 Ready 40m v1.10.2
5、安照这种方式,我们可以横向添加多个节点。
创建应用
这里使用mysql 和tomcat 作为示例。
创建mysql的应用
1、创建一个mysql.yaml的文件:
apiVersion: v1
kind: ReplicationController # 指定kind类型为RC
metadata:
name: mysql # RC的名称,全局唯一
spec:
replicas: 1 # pod 副本数量
selector:
app: mysql # 符合目标的Pod拥有此标签
template: # 根据此模板,创建Pod的副本(实例)
metadata:
labels:
app: mysql # Pod 副本拥有的标签,对应RC的Selector
spec:
containers: # Pod 内 容器定义的部分
- name: mysql # 容器名称
image: mysql # 容器镜像
ports:
- containerPort: 3306 # 容器应用监听的端口
env: # 注入容器的环境变量
- name: MYSQL_ROOT_PASSWORD
value: "123456"
2、使用kubectl 命令发布到k8s集群,在Master执行:
kubectl create -f mysql.yaml
3、查看容器,RC和pod状态:
# node-2节点上创建了两个容器,一个mysql 和 pause
[root@node-2 ~]# docker ps | grep mysql
f951c5e1043f mysql@sha256:d60c13a2bfdbbeb9cf1c84fd3cb0a1577b2bbaeec11e44bf345f4da90586e9e1 "docker-entrypoint..." 19 minutes ago Up 19 minutes k8s_mysql_mysql-kfkdd_default_6b18de55-5b14-11e8-9cc0-000c29c83e1f_0
dd17c26dad8c k8s.gcr.io/pause-amd64:3.1 "/pause" 20 minutes ago Up 20 minutes k8s_POD_mysql-kfkdd_default_6b18de55-5b14-11e8-9cc0-000c29c83e1f_0
# 查看 RC,Master上执行
[root@node-1 ~]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 1 1 1 22m
# 查看pod
[root@node-1 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-kfkdd 1/1 Running 0 22m
4、创建service, 定义个mysql-service.yaml的文件:
apiVersion: v1
kind: Service # 说明这是一个K8S Service
metadata:
name: mysql # Service 的全局唯一名称
spec:
ports:
- port: 3306 # service 提供的服务端口号
selector: # 定义有哪些pod 对应到此服务
app: mysql
5、创建service:
[root@node-1 ~]# kubectl create -f mysql-service.yaml
service "mysql" created
6、查看service,这里自动分配了一个ip和pod 中的虚端口。由于Kubernetes是使用kubeadm 以容器的方式启动,所以有一个kubernetes的服务。
[root@node-1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 18h
mysql ClusterIP 10.110.213.104 3306/TCP 17s
创建tomcat 应用
1、创建rc 文件tomcat.yaml:
apiVersion: v1
kind: ReplicationController
metadata:
name: myweb
spec:
replicas: 2 # 指定两个副本
selector:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- name: myweb
image: kubeguide/tomcat-app:v1
ports:
- containerPort: 8080
2、创建RC,并验证:
[root@node-1 ~]# kubectl create -f tomcat.yaml
replicationcontroller "myweb" created
[root@node-1 ~]# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 1 1 1 1h
myweb 2 2 2 8m
[root@node-1 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-kfkdd 1/1 Running 0 1h
myweb-qqmp8 1/1 Running 0 7m
myweb-sz64h 1/1 Running 0 7m
[root@node-2 ~]# docker ps|grep myweb
c98ce89ce2c2 kubeguide/tomcat-app@sha256:7a9193c2e5c6c74b4ad49a8abbf75373d4ab76c8f8db87672dc526b96ac69ac4 "catalina.sh run" 15 minutes ago Up 15 minutes k8s_myweb_myweb-qqmp8_default_3dc7da86-5b20-11e8-9cc0-000c29c83e1f_0
cbdc283633ce kubeguide/tomcat-app@sha256:7a9193c2e5c6c74b4ad49a8abbf75373d4ab76c8f8db87672dc526b96ac69ac4 "catalina.sh run" 16 minutes ago Up 16 minutes k8s_myweb_myweb-sz64h_default_3dc89ceb-5b20-11e8-9cc0-000c29c83e1f_0
f8416f5e72e9 k8s.gcr.io/pause-amd64:3.1 "/pause" 17 minutes ago Up 17 minutes k8s_POD_myweb-qqmp8_default_3dc7da86-5b20-11e8-9cc0-000c29c83e1f_0
70b6cd00594a k8s.gcr.io/pause-amd64:3.1 "/pause" 17 minutes ago Up 17 minutes k8s_POD_myweb-sz64h_default_3dc89ceb-5b20-11e8-9cc0-000c29c83e1f_0
3、 创建Service,定义 tomcat-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort # 定义外网访问模式
ports:
- port: 8080
nodePort: 30001 # 外网访问的端口,映射的本地宿主机端口
selector:
app: myweb
4、验证:
[root@node-1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 19h
mysql ClusterIP 10.110.213.104 3306/TCP 1h
myweb NodePort 10.102.243.124 8080:30001/TCP 5m
[root@node-1 ~]# netstat -lntp|grep 30001
tcp6 0 0 :::30001 :::* LISTEN 2763/kube-proxy
[root@node-2 ~]# netstat -lntp|grep 30001
tcp6 0 0 :::30001 :::* LISTEN 2362/kube-proxy
通过访问Master或node节点的30001端口可以访问到tomcat默认页面。
5、如果要删除一个service 执行:
kubectl delete service mysql
提示:删除pod 后会自动创建一个新的pod,删除node上运行的容器也会自动创建一个新的容器。