部署说明
此篇文章介绍的是 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 <<EOF> /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 <<EOF> /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 <none> 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 <none> 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 <none> 443/TCP 18h
- mysql ClusterIP 10.110.213.104 <none> 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 <none> 443/TCP 19h
- mysql ClusterIP 10.110.213.104 <none> 3306/TCP 1h
- myweb NodePort 10.102.243.124 <none> 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 上运行的容器也会自动创建一个新的容器.
来源: http://blog.51cto.com/tryingstuff/2118176