前言
在探索容器应用治理的过程中,我们进行了很多的实践,我们尝试了CoreOS的Fleet、Docker Swarm,我们也参考了诸多厂商的Docker集群实践方案,最终我们发现在绝大部分的成熟应用案例中,Kubernetes似乎是相当好的选择。它提供的应用部署、维护、 扩展机制等功能,可以方便地管理跨主机运行容器化的应用,Kubernetes背后有Google,RedHat,CoreOS等诸多大公司的支持。
架构
本次部署我们采用的是单Master多Minion结构,下面是我的部署全过程,希望能给读者提供一些思路,如果有任何更好的方法或者有其他方案讨论,欢迎使用Email或者Github留言。
资源
操作系统: CentOS Linux release 7.2.1511 (Core)
容器引擎: Docker(Kubernetes还支持Rkt)
容器网络: Flannel
部署形式: 1主多从(Master没做HA),主机Systemd运行方式(Kubernetes还支持容器部署和单机部署),单集群(Kubernetes还支持多集群部署)。
资源下载
Docker初始化
主要是对Kubernetes Minion节点进行一些配置初始化,有一些配置是必须的,有一些配置不是必须的,接下来我会标记好,当然配置可能还有更好的方式,大家可以自行研究。
清除防火墙规则和关闭Selinux
iptables -X
iptables -F
iptables -Z
vim /etc/sysconfig/selinux
SELINUX=disabled #如果你有比较高的安全要求,不建议关闭Selinux,在配置和使用Kubernetes的过程中配置好相应Selinux条文即可
配置Docker存储
默认CentOS7下Docker使用的Device Mapper设备默认使用loopback设备,从网友们的反馈看来,这个存储的问题比较多,官方也不推荐使用这一种存储方式,如果你只是做测试,可以省略修改,以下是docker存储方式修改为direct-lvm的方式,完整的手工配置比较复杂,可以参考Docker and the Device Mapper storage driver。在CentOS7中,提供了docker-storage-setup工具用于简化配置,准备一个空磁盘,以下我使用的是vdb.。
编辑/etc/sysconfig/docker-storage-setup
文件加入以下内容
DEVS=/dev/vdb
VG=dk-vg
SETUP_LVM_THIN_POOL=yes
然后关闭Docker,并生成相应的分区,清理旧数据,再启动Docker。
systemctl stop docker
docker-storage-setup
rm -rf /var/lib/docker
systemctl start docker
这时候,通过Docker info|grep "Pool Name"
应该可以看到存储信息,便可以判断是否配置成功。
添加私有仓库
如果你有自己的私有仓库,又没有配置登录设置,那么你需要修改配置文件允许你的Docker访问私有仓库
编辑/etc/sysconfig/docker
,为Docker选项加入配置.
#支持多个私有仓库地址
OPTIONS='--insecure-registry 10.201.78.110:5000 --insecure-registry 10.201.78.111:5000 --log-driver=journald'
内核参数
以下参数用于开启Linux内核的一些桥接网卡的Iptables功能。
vim /etc/sysctl.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-arptables = 1
sysctl -p
#同样也可以在docker info中看到是否看起成功,无须重启
配置etcd
Kubernetes和flannel都需要用到etcd,所以我们先配置好etcd,你可以选择集群或者单机模式,以下我配置etcd为三节点集群(通常建议节点数为3、5、7,利于集群内的选举)。下载的etcd是编译号的二进制文件,可直接运行,方便起见,你只需要将etcd
和etcdctl
文件放到/usr/bin
或/bin
中
编辑/usr/lib/systemd/system/etcd.service
文件,并启动etcd。
[Unit]
Description=etcd
[Service]
ExecStart=/usr/bin/etcd --name infra0 --initial-advertise-peer-urls http://10.201.78.110:7001 \
--listen-peer-urls http://10.201.78.110:7001 \
--listen-client-urls http://10.201.78.110:4001,http://127.0.0.1:4001 \
--advertise-client-urls http://10.201.78.110:4001 \
--initial-cluster-token etcd-cluster \
--initial-cluster infra0=http://10.201.78.110:7001,infra1=http://10.201.78.111:7001,infra2=http://10.201.78.112:7001 \
--data-dir /apps/data/etcd \
--initial-cluster-state new
[Install]
WantedBy=multi-user.target
确认启动没有报错后,其他两个节点编辑同样的文件,修改节点名(这里的"infra0")和IP地址,然后启动etcd便可以了,你可以通过etcdctl cluster-health
查看集群状态,通过etcdctl member list
查看集群节点。
如果启动没有报错,添加flannel需要的配置。也就是规划网段的配置。
etcdctl mk /coreos.com/network/config '{"Network":"172.17.0.0/16", "SubnetMin": "172.17.1.0", "SubnetMax": "172.17.254.0"}'
配置flannel网络
配置flannel
其实flannel也是和etcd一样,不用安装的,直接从官方下载二进制执行文件就可以了,当然,你也可以自己编译
,首先配置好flannel,再配置docker,使其使用flannel网络。
编辑/usr/lib/systemd/system/flanneld.service
(主要修改成你的flanneld程序路径):
[Unit]
Description=flannel
[Service]
ExecStart=/opt/flannel/flanneld \
-etcd-endpoints=http://172.16.164.5:4001 #etcd地址
[Install]
WantedBy=multi-user.target
systemctl start flanneld
正常情况下,使用ip a s flannel0
可以查看到flannel的桥接网卡已经起来了。
配置docker
首先生成Docker参数,在flannel程序包中有脚本,执行/opt/flannel/mk-docker-opts.sh -c
,回生成docker的启动参数,默认保存到/run/docker_opts.env,也可以使用-i
参数,生成的样式不一样,正常来说,把这些参数加到Docker的启动参数中,重启Docker就可以了,但是方便起见,我希望这个脚本加入到Docker中,每次重启Docker都能重新生成这个配置,避免网络变化导致参数不对,所以我修改了Docekr的启动配置:/usr/lib/systemd/system/docker.service
:(如果你不是使用引入文件的方式,就把配置项加到docker启动参数里)
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target
After=flanneld.service
Requires=flanneld.service
Wants=docker-storage-setup.service
[Service]
Type=notify
NotifyAccess=all
EnvironmentFile=/run/docker_opts.env #+ 引入环境变量
EnvironmentFile=-/etc/sysconfig/docker
EnvironmentFile=-/etc/sysconfig/docker-storage
EnvironmentFile=-/etc/sysconfig/docker-network
Environment=GOTRACEBACK=crash
ExecStartPre=/opt/flannel/mk-docker-opts.sh -c #+ 执行脚本,备下次使用
ExecStart=/bin/sh -c '/usr/bin/docker daemon $OPTIONS \
$MK_DOCKER_OPTS \ #+ 我脚本中的变量名称我改成了这个,并在脚本中加入清理这个变量,否则每次生成的配置都会叠在一起重复
$DOCKER_OPTS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$ADD_REGISTRY \
$BLOCK_REGISTRY \
$INSECURE_REGISTRY \
2>&1 | /usr/bin/forward-journald -tag docker'
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
MountFlags=slave
TimeoutStartSec=0
Restart=on-failure
StandardOutput=null
StandardError=null
[Install]
WantedBy=multi-user.target
之后重启docker,正常的话,使用ip a
可以看到docker0网卡和flannel0网卡是在同一个网段。多个节点配置好后,不同主机上运行容器,容器之间应该也是可以直接访问。
到此,基础环境就准备好了
安装Kubernetes
单集群Kubernets,也不做Master HA的话,配置还是比较简单的,但是很多用户都反映安装复杂,所以Kubernetes每一次版本更新,都升级更新安装方式,单机部署、Docker部署包、多集群部署等等让人眼花缭乱,接下来采用的是最无脑的方式,直接虚拟机部署。
安装比较简单,都是二进制文件,只需要放到对应的目录启动即可。
首先,所有机器添加好IP变量,便于引用,在资源列表中的setup-network-environment这个工具执行后就是会生成这个配置文件的,之后再手动加上MASTER_IP
设置/etc/network-environment
如果不使用工具,自己写上就好了。
LO_IPV4=127.0.0.1
ETH0_IPV4=172.16.164.6
DEFAULT_IPV4=172.16.164.6
DOCKER0_IPV4=172.17.67.1
FLANNEL0_IPV4=172.17.67.0
MASTER_IP=172.16.164.5
部署Master
所有服务文件在压缩包的这个路径kubernetes/server/kubernetes-server-linux-amd64.tar.gz
,解压出来就是可以部署的二进制文件、Docker镜像等,这里只需要用到二进制文件,下面等服务,都是只需要设置好systemd(/usr/lib/systemd/system/service-name.service)配置,启动即可。
配置SSL(可选)
首先配置SSL证书,如果不配置的话,Kubernetes启动的时候会自动创建,但是创建的证书当然是不会加入我们的master地址的,所以这里自己创建。
mkdir -p /etc/kubernetes/ssl
cd /etc/kubernetes/ssl
openssl genrsa -out ca-key.pem 2048
openssl req -x509 -new -nodes -key ca-key.pem -days 10000 -out ca.pem -subj "/CN=kube-ca"
vim openssl.cnf
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
DNS.5 = m #注意填你自己的Master 主机名
IP.1 = 10.0.0.1
IP.2 = 10.201.78.110 #注意填你自己的Master IP
openssl genrsa -out apiserver-key.pem 2048
openssl req -new -key apiserver-key.pem -out apiserver.csr -subj "/CN=kube-apiserver" -config openssl.cnf
openssl x509 -req -in apiserver.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out apiserver.pem -days 365 -extensions v3_req -extfile openssl.cnf
kube-apiserver
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
Requires=etcd.service
After=etcd.service
[Service]
EnvironmentFile=/etc/network-environment
ExecStart=/opt/bin/kube-apiserver \
--client_ca_file=/etc/kubernetes/ssl/ca.pem \
--tls-private-key-file=/etc/kubernetes/ssl/apiserver-key.pem \
--tls-cert-file=/etc/kubernetes/ssl/apiserver.pem \
--service-account-key-file=/etc/kubernetes/ssl/apiserver-key.pem \
--service-account-lookup=false \
--admission-control=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota \
--runtime-config=api/v1 \
--allow-privileged=true \
--insecure-bind-address=0.0.0.0 \
--insecure-port=8080 \
--kubelet-https=true \
--secure-port=6443 \
--service-cluster-ip-range=10.0.0.0/16 \
--etcd-servers=http://127.0.0.1:4001 \
--public-address-override=${DEFAULT_IPV4} \
--logtostderr=true \
--cors-allowed-origins='.*'
Restart=always
RestartSec=10
systemctl start kube-apiserver
kube-controller-manager
[Unit]
Description=kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
Requires=kbapi.service
After=kbapi.service
[Service]
ExecStart=/opt/bin/kube-controller-manager \
--service-account-private-key-file=/etc/kubernetes/ssl/apiserver-key.pem \
--root-ca-file=/etc/kubernetes/ssl/ca.pem \
--master=127.0.0.1:8080 \
--logtostderr=true
Restart=always
RestartSec=10
systemctl start kube-controller-manager
kube-scheduler
[Unit]
Description=kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
Requires=kbapi.service
After=kbapi.service
[Service]
ExecStart=/opt/bin/kube-scheduler \
--master=127.0.0.1:8080
Restart=always
RestartSec=10
systemctl start kube-scheduler
kube-dns
[Unit]
Description=Kubernetes DNS Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=kbapi.service
Requires=kbapi.service
[Service]
ExecStart=/opt/bin/kube-dns \
--dns-port=53 \
--domain=cluster.local \
--kube-master-url=http://10.201.78.110:8080 #kube-api地址
Restart=on-failure
RestartSec=10
systemctl start kube-dns
安装Minion
安装方式和Master差不多,只是更加简单,开启两个进程即可,同样,记得添加好/etc/network-environment
配置 。
Kubelet
[Unit]
Description=kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
EnvironmentFile=/etc/network-environment
ExecStart=/opt/bin/kubelet \
--address=0.0.0.0 \
--port=10250 \
--hostname-override=${DEFAULT_IPV4} \
--api-servers=${MASTER_IP}:8080 \
--allow-privileged=true \
--logtostderr=true \
--cadvisor-port=4194 \
--cluster_dns=10.201.78.110 \
--cluster_domain=cluster.local \
--healthz-bind-address=0.0.0.0 \
--healthz-port=10248
Restart=always
RestartSec=10
systemctl start Kubelet
kube-proxy
[Unit]
Description=kubernetes Proxy
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
[Service]
EnvironmentFile=/etc/network-environment
ExecStart=/opt/bin/kube-proxy \
--master=${MASTER_IP}:8080 \
--proxy-mode=iptables \
--logtostderr=true
Restart=always
RestartSec=10
systemctl start kube-proxy
结束
到此,Kubernetes的部署就结束了,通常来说,你在Master中之行kubectl get nodes
就能看到集群节点就表示这个集群可用了。当然,这只是革命的开始,尽管Kubernetes解决了很多Docker引入的问题,但是如果你想要在生产环境中使用Kubernetes,你还要解决的问题有很多,比如性能、监控、日志、更新等等,在之后的文章了里,再细细研究了。