CentOS7搭建Kubernetes 1.3


前言

在探索容器应用治理的过程中,我们进行了很多的实践,我们尝试了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还支持多集群部署)。

资源下载

Kubernetes

etcd

flannel

setup-network-environment(可选)

Docker初始化

主要是对Kubernetes Minion节点进行一些配置初始化,有一些配置是必须的,有一些配置不是必须的,接下来我会标记好,当然配置可能还有更好的方式,大家可以自行研究。

清除防火墙规则和关闭Selinux

iptables -X
iptables -F
iptables -Z
vim /etc/sysconfig/selinux
SELINUX=disabled

配置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是编译号的二进制文件,可直接运行,方便起见,你只需要将etcdetcdctl文件放到/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=kube-apiserver.service
After=kube-apiserver.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
[Install]
WantedBy=multi-user.target

systemctl start kube-controller-manager

kube-scheduler
[Unit]
Description=kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
Requires=kube-apiserver.service
After=kube-apiserver.service

[Service]
ExecStart=/opt/bin/kube-scheduler \
	--master=127.0.0.1:8080
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target

systemctl start kube-scheduler

kube-dns
[Unit]
Description=Kubernetes DNS Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=kube-apiserver.service
Requires=kube-apiserver.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
[Install]
WantedBy=multi-user.target

systemctl start kube-dns

systemctl enable kube-dns kube-apiserver kube-controller-manager kube-scheduler

安装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
[Install]
WantedBy=multi-user.target

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
[Install]
WantedBy=multi-user.target

systemctl start kube-proxy

systemctl enable kube-proxy Kubelet

结束

到此,Kubernetes的部署就结束了,通常来说,你在Master中之行kubectl get nodes就能看到集群节点就表示这个集群可用了。当然,这只是革命的开始,尽管Kubernetes解决了很多Docker引入的问题,但是如果你想要在生产环境中使用Kubernetes,你还要解决的问题有很多,比如性能、监控、日志、更新等等,在之后的文章了里,再细细研究了。

支持一下咯( ・ั﹏・ั)(支付宝)

支付宝