在EC2上使用Kubernetes的Fedora Atomic Host进行Docker容器的集群化
首先
因为Redhat似乎对此作为一个真正的项目持有热情,所以如果在企业内使用的话,我认为Project Atomic可能是最有希望的选择。我尝试使用Fedora Atomic Host在EC2上对Docker容器进行了集群试验。
标题写着是关于Kubernetes的,但我还会试试包含在Atomic中的Cockpit等其他选项。
有关于Project Atomic的身份是通过这张幻灯片《在RHEL上使用Docker和Project Atomic – #Dockerjp 4入门》可以非常清楚地了解到。
每个软件的版本在试用时的时间点。
这是很久以前的事了,我尝试过的时间是2015年2月17日,所以下面提供的信息都是基于当时的情况。
这是使用Fedora-Cloud-Atomic-20141203-21.x86_64进行rpm-ostree upgrade所安装的最新版本。
-
- Kubernetes: 0.7.0
-
- Cockpit: 0.27
-
- etcd: 0.4.6
-
- docker: 1.4.1
- cAdvisor: 0.6.2
由于以下是最新的,所以相当过时。
嗯,每天都在不断升级,所以也没办法。
-
- Kubernetes: 0.10.1
-
- Cockpit: 0.38
-
- etcd: 2.0.3
-
- docker: 1.5.0
- cAdvisor: 0.9.0
请理解,如果你现在执行 “rpm-ostree upgrade” 指令,将会安装更新版本,并且最新版本也会变化。但由于本文内容试验时的时间点不同,请谅解。
EC2实例的启动
在中国有RHEL Atomic和CentOS Atomic可供选择,但本次我们将尝试使用开发速度最快的Fedora Atomic。
选择您喜欢的地区AMI,从Fedora Cloud下载页面中底部的《Atomic Cloud HVM》部分。
请按常规方式进行启动。
请您在以后组装群集时,为安全组指定一个合适的名称。
登录SSH时,请使用用户fedora。
$ ssh -i ~/.ssh/key.pem fedora@1.2.3.4
由于 Kubernetes 等版本过旧,需要更新软件包。
$ sudo rpm-ostree upgrade
$ sudo systemctl reboot
尝试运行Docker容器
Docker正常运行。
$ systemctl list-units | grep docker
sys-devices-virtual-net-docker0.device loaded active plugged /sys/devices/virtual/net/docker0
sys-subsystem-net-devices-docker0.device loaded active plugged /sys/subsystem/net/devices/docker0
docker.service loaded active running Docker Application Container Engine
我尝试运行 Docker。
$ sudo docker run centos /bin/echo "Hello Atomic"
Unable to find image 'centos' locally
Pulling repository centos
dade6cb4530a: Download complete
511136ea3c5a: Download complete
5b12ef8fd570: Download complete
Status: Downloaded newer image for centos:latest
Hello Atomic
动了。
尝试操纵驾驶舱
Cockpit是一个可以管理服务器和Docker容器的Web界面。
在Atomic中,默认启用。
由于Cockpit在9090端口运行,因此需要在安全组中开放9090端口。
由于以操作系统的用户账户登录,我们需要为root用户设置密码。
$ sudo passwd root
请访问 http://1.2.3.4:9090
使用密码以root用户身份登录后,将显示集群中服务器的列表。
您可以监控各资源的使用情况。
可以管理Docker容器镜像。
Docker容器的管理有许多不同的功能。
启动和停止容器
(很遗憾,无法指定docker run的选项。)
为每个容器设置系统资源限制
从Docker Hub上拉取镜像
除此之外,您还可以通过Web操作服务器终端、查看所有容器的CPU和内存使用率以及通过镜像启动容器等等。
尝试运行cAdvisor
cAdvisor是一个用于监视服务器容器的工具。它默认不会启动,所以我们需要手动启动它。
$ sudo systemctl start cadvisor
发生了动作。
$ sudo journalctl -f -l -xn -u cadvisor
-- Logs begin at Mon 2015-02-16 13:19:03 UTC. --
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.443643 1331 manager.go:77] cAdvisor running in container: "/"
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.444400 1331 manager.go:91] Machine: {NumCores:1 MemoryCapacity:1040220160 Filesystems:[{Device:/dev/xvda1 Capacity:198902784}]}
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.444749 1331 manager.go:98] Version: {KernelVersion:3.18.6-200.fc21.x86_64 ContainerOsVersion:Fedora 21 (Twenty One) DockerVersion:Unknown CadvisorVersion:0.6.2}
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: E0218 02:49:49.444973 1331 cadvisor.go:62] Docker registration failed: unable to communicate with docker daemon: dial unix /var/run/docker.sock: no such file or directory.
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.445578 1331 factory.go:78] Registering Raw factory
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.446156 1331 manager.go:394] Added container: "/" (aliases: [], namespace: "")
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.446334 1331 manager.go:131] Starting recovery of all containers
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.446922 1331 manager.go:136] Recovery completed
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.447805 1331 cadvisor.go:103] Starting cAdvisor version: "0.6.2" on port 4194
Feb 18 02:49:49 ip-172-30-0-246.ec2.internal cadvisor[1331]: I0218 02:49:49.448019 1331 container.go:141] Start housekeeping for container "/"
因为在4194端口上运行,所以需要打开4194端口,并访问http://<IP地址>:4194。
您可以查看服务器资源和Docker容器资源。
由于还有API,您可以将其用于监控机制。
(当我尝试查看Docker容器时,不知何故出现了错误,但我暂时决定忽略这一点。)
最新版本(v0.9.0)可以监控网络和磁盘IO。(请参阅google/cadvisor的发布说明)
Cockpit和cAdvisor的功能有点重叠,但cAdvisor是Kubernetes使用的,所以没办法。
试着运行Kubernetes
Kubernetes是一种用于集群化Docker容器的工具,类似于CoreOS的fleet。
使用原子主机测试Kubernetes – 参考Project Atomic运行Kubernetes。
在这个版本(etcd 0.4.6)中,默认配置下etcd无法启动,因此需要修改配置。
解除/etc/etcd/etcd.conf中的name注释。
$ sudo vi /etc/etcd/etcd.conf
name = "default-name"
由于 Kubernetes 在安装时不会自动运行,所以需要手动启动。
$ sudo su
# for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler docker kube-proxy.service kubelet.service; do
systemctl restart $SERVICES
systemctl enable $SERVICES
systemctl status $SERVICES
done
确认etcd已启动。
$ curl http://localhost:4001/version
etcd 0.4.6
确认Kubernetes的apiserver已启动。
$ curl http://localhost:8080/version
{
"major": "0",
"minor": "7+",
"gitVersion": "v0.7.0-18-g52e165a4fd720d-dirty",
"gitCommit": "52e165a4fd720d1703ebc31bd6660e01334227b8",
"gitTreeState": "dirty"
}
我还没有组建群集,所以迷你恶棍只有我一个。
$ kubectl get minions
NAME LABELS
127.0.0.1 <none>
我将启动Apache的pod。
$ vi apache.json
{
"id": "fedoraapache",
"kind": "Pod",
"apiVersion": "v1beta1",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "fedoraapache",
"containers": [{
"name": "fedoraapache",
"image": "fedora/apache",
"ports": [{
"containerPort": 80,
"hostPort": 80
}]
}]
}
},
"labels": {
"name": "fedoraapache"
}
}
$ kubectl create -f apache.json
I0216 16:00:07.854098 6240 restclient.go:133] Waiting for completion of operation 2
fedoraapache
Apache开始运行了。
$ kubectl get pod fedoraapache
NAME IMAGE(S) HOST LABELS STATUS
fedoraapache fedora/apache 127.0.0.1/ name=fedoraapache Running
$ curl http://localhost/
Apache
使用Kubernetes构建集群环境。
参考GoogleCloudPlatform / kubernetes的kubernetes / fedora_manual_config.md文件,手动进行配置。
增加一个实例,一个设为主节点(master),其余设为从节点(minion),组成集群。具体配置如下:
fed-master = 172.30.0.246
fed-minion = 172.30.0.43
请将此时添加的实例全部分配到同一个安全组中。
添加的实例将更新软件包。
$ sudo rpm-ostree upgrade
$ sudo systemctl reboot
尽管上述文章中提到Fedora Atomic不需要此功能,但由于仍出现相同错误,我们将进行错误修复。
$ sudo su
# sed -e "s/docker\.socket/docker\.service/g" /usr/lib/systemd/system/kubelet.service > /etc/systemd/system/kubelet.service
# systemctl daemon-reload
将服务器的IP地址写入所有节点的hosts文件中。(如果主机名已经在DNS服务器中注册,则不需要这一步。)
$ sudo su
# echo "172.30.0.246 fed-master
172.30.0.43 fed-minion" >> /etc/hosts
只需更改KUBE_ETCD_SERVERS的设置,就应该可以将所有节点的/etc/kubernetes/config更改如下。
# Comma seperated list of nodes in the etcd cluster
KUBE_ETCD_SERVERS="--etcd_servers=http://fed-master:4001"
# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"
# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=0"
# Should this cluster be allowed to run privleged docker containers
KUBE_ALLOW_PRIV="--allow_privileged=false"
在同一个安全组中允许所有TCP通信。
设置主节点
将之前启动的Apache Pod停止。
$ kubectl delete -f apache.json
fedoraapache
停止不必要的服务在主节点。
$ sudo su
# for SERVICES in kube-proxy kubelet docker; do
systemctl stop $SERVICES
systemctl disable $SERVICES
systemctl status $SERVICES
done
将master节点的/etc/kubernetes/apiserver更改为如下所示。
# The address on the local server to listen to.
KUBE_API_ADDRESS="--address=0.0.0.0"
# The port on the local server to listen on.
KUBE_API_PORT="--port=8080"
# How the replication controller and scheduler find the kube-apiserver
KUBE_MASTER="--master=http://fed-master:8080"
# Port minions listen on
KUBELET_PORT="--kubelet_port=10250"
# Address range to use for services
KUBE_SERVICE_ADDRESSES="--portal_net=10.254.0.0/16"
# Add you own!
KUBE_API_ARGS=""
将master节点的/etc/kubernetes/controller-manager文件更改如下。
# Comma seperated list of minions
KUBELET_ADDRESSES="--machines=fed-minion"
在主节点上启动相关服务。
$ sudo su
# for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler; do
systemctl restart $SERVICES
systemctl enable $SERVICES
systemctl status $SERVICES
done
小黄人节点的配置
将/etc/kubernetes/kubelet配置为以下方式。
# The address for the info server to serve on
KUBELET_ADDRESS="--address=0.0.0.0"
# The port for the info server to serve on
KUBELET_PORT="--port=10250"
# You may leave this blank to use the actual hostname
KUBELET_HOSTNAME="--hostname_override=fed-minion"
# Add your own!
KUBELET_ARGS=""
启动必要的服务。
$ sudo su
# for SERVICES in kube-proxy kubelet docker; do
systemctl restart $SERVICES
systemctl enable $SERVICES
systemctl status $SERVICES
done
请在master节点上运行以下命令,以确保fed-minion已添加到集群中。
$ kubectl get minions
NAME LABELS
fed-minion <none>
我尝试创建一个Apache Pod。
$ kubectl create -f apache.json
fedoraapache
我在fed-minion节点上成功启动了。
$ kubectl get pod fedoraapache
NAME IMAGE(S) HOST LABELS STATUS
fedoraapache fedora/apache fed-minion/ name=fedoraapache Running
$ curl http://fed-minion/
Apache
组装了集群配置。
然而,在这里查看Cockpit时,只显示了主节点。由于最新的Cockpit中已经写明了与Kubernetes集成和多主机支持,所以可能有些不同。(见Releases · cockpit-project/cockpit)
将迷你角色分为两个。
请按照与上述相同的步骤添加一个实例。
fed-master = 172.30.0.246
fed-minion = 172.30.0.43
fed-minion-2 = 172.30.0.11
在fed-minion-2的/etc/hosts文件中,设置每个节点的IP地址。
# echo "172.30.0.246 fed-master
172.30.0.43 fed-minion
172.30.0.11 fed-minion-2" >> /etc/hosts
在fed-master和fed-minion的/etc/hosts中添加以下设置。
# echo "172.30.0.11 fed-minion-2" >> /etc/hosts
将fed-minion-2添加到fed-master的/etc/kubernetes/controller-manager文件的以下位置。
KUBELET_ADDRESSES="--machines=fed-minion,fed-minion-2"
修改fed-minion-2的/etc/kubernetes/config文件中的KUBE_ETCD_SERVERS如下。
KUBE_ETCD_SERVERS="--etcd_servers=http://fed-master:4001"
我将对fed-minion-2的/etc/kubernetes/kubelet文件进行以下两处更改。
KUBELET_ADDRESS="--address=0.0.0.0"
KUBELET_HOSTNAME="--hostname_override=fed-minion-2"
启动 fed-minion-2 所需的服务。
$ sudo su
# for SERVICES in kube-proxy kubelet docker; do
systemctl restart $SERVICES
systemctl enable $SERVICES
systemctl status $SERVICES
done
重启fed-master服务。
$ sudo su
# for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler; do
systemctl restart $SERVICES
systemctl enable $SERVICES
systemctl status $SERVICES
done
fed-minion-2已被添加到集群中。
$ kubectl get minions
NAME LABELS
fed-minion-2 <none>
fed-minion <none>
运行Guestbook示例
再次,参考项目Atomic Host,使用Atomic Host测试Kubernetes,以这种集群配置运行Kubernetes的Guestbook示例。
Guestbook是一个使用PHP和Redis构建的演示应用程序,当写入评论时,评论会被保存在Redis中。
前端容器有3个,Redis主服务器有1个,只读的Redis从服务器有2个。PHP应用程序从从服务器读取数据,将数据写入主服务器。
由于本次测试只使用两个小黄人,因此前端也将减少到两个。以下是配置的样式。
发布 v0.7.0 发布候选版 · 从 GoogleCloudPlatform/kubernetes 的 Git 仓库下载 Kubernetes。确保安装的版本与当前版本相同,即 v0.7.0。
请注意,以下所有操作都将在 fed-master 节点上进行。
$ curl -L -O https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v0.7.0/kubernetes.tar.gz
$ tar zxvf kubernetes.tar.gz
$ cd kubernetes/examples/guestbook
启动Redis的主节点Pod。
$ kubectl create -f redis-master.json
等待 pod redis-master 运行完成。
$ kubectl get pod redis-master
NAME IMAGE(S) HOST LABELS STATUS
redis-master dockerfile/redis fed-minion/ name=redis-master Running
创建一个用于与标记为”redis-master”的Pod进行通信的服务。
Kubernetes的Service是用来中介容器之间通信的负载均衡器。您可以通过环境变量来使用该服务。
$ kubectl create -f redis-master-service.json
确认服务已创建。
$ kubectl get service redis-master
NAME LABELS SELECTOR IP PORT
redis-master name=redis-master name=redis-master 10.254.104.212 6379
这样,所有的Pod都可以通过10.254.104.212:6379访问redis主机了。
Redis主节点的配置为单个Pod,而Redis从节点的配置为两个Pod。从节点的配置方式被称为复制Pod,并由ReplicationController进行管理。
用下面的命令启动Redis从属节点。
$ kubectl create -f redis-slave-controller.json
在其中两个Pod中运行了一个ReplicationController。Redis slave 在fed-minion和fed-minion-2中分别运行一个。
$ kubectl get replicationController redisSlaveController
NAME IMAGE(S) SELECTOR REPLICAS
redisSlaveController brendanburns/redis-slave name=redisslave 2
$ kubectl get pods -l "name=redisslave"
NAME IMAGE(S) HOST LABELS STATUS
36300455-b6a8-11e4-8444-12e8df01b920 brendanburns/redis-slave fed-minion-2/ name=redisslave,uses=redis-master Running
3630b03b-b6a8-11e4-8444-12e8df01b920 brendanburns/redis-slave fed-minion/ name=redisslave,uses=redis-master Running
Redis从属节点的Docker容器命令如下,通过环境变量获取Redis主节点的主机名和端口号。该解析由redis-master服务完成。
redis-server --slaveof ${REDIS_MASTER_SERVICE_HOST:-$SERVICE_HOST} $REDIS_MASTER_SERVICE_PORT
当Redis从属Pod变为运行状态时,将创建Redis从属Service。
$ kubectl create -f redis-slave-service.json
$ kubectl get service redisslave
NAME LABELS SELECTOR IP PORT
redisslave name=redisslave name=redisslave 10.254.197.146 6379
与Redis主节点服务一样,任何一个Pod内部都可以通过10.254.197.146:6379访问Redis从节点。该服务将进行负载均衡,可透明地访问两个Pod。
最后我们将创建一个前端Pod。在示例中,前端Pod由3个Pod组成,但由于仅有2个minion,所以我们将frontend-controller.json中的副本数从3改为2。
"replicas": 2,
最终我们将创建前端Pod。
$ kubectl create -f frontend-controller.json
$ kubectl get replicationController frontendController
NAME IMAGE(S) SELECTOR REPLICAS
frontendController kubernetes/example-guestbook-php-redis name=frontend 2
$ kubectl get pods -l "name=frontend"
NAME IMAGE(S) HOST LABELS STATUS
b8947bd1-b6ac-11e4-8444-12e8df01b920 kubernetes/example-guestbook-php-redis fed-minion-2/ name=frontend,uses=redisslave,redis-master Running
b89561c0-b6ac-11e4-8444-12e8df01b920 kubernetes/example-guestbook-php-redis fed-minion/ name=frontend,uses=redisslave,redis-master Running
在PHP代码中,我们使用getenv(‘REDIS_MASTER_SERVICE_PORT’)从环境变量中获取Redis主服务器和从服务器的主机名和端口。详细信息请查看guestbook/php-redis/index.php。
所有的Pod,Service和Replication Controller都已经启动。
$ kubectl get pods
NAME IMAGE(S) HOST LABELS STATUS
redis-master dockerfile/redis fed-minion/ name=redis-master Running
36300455-b6a8-11e4-8444-12e8df01b920 brendanburns/redis-slave fed-minion-2/ name=redisslave,uses=redis-master Running
3630b03b-b6a8-11e4-8444-12e8df01b920 brendanburns/redis-slave fed-minion/ name=redisslave,uses=redis-master Running
b8947bd1-b6ac-11e4-8444-12e8df01b920 kubernetes/example-guestbook-php-redis fed-minion-2/ name=frontend,uses=redisslave,redis-master Running
b89561c0-b6ac-11e4-8444-12e8df01b920 kubernetes/example-guestbook-php-redis fed-minion/ name=frontend,uses=redisslave,redis-master Running
当前运行的前端fed-minion将通过8000端口访问fed-minion-2,从而使Guestbook应用程序运行。(请事先在EC2安全组中打开8000端口。)
尝试自动故障转移
试着停止fed-minion实例。
$ kubectl get minions
NAME LABELS
fed-minion-2 <none>
小黄人数量减少了。
$ kubectl get pods
F0217 15:08:54.544116 1605 get.go:75] The requested resource does not exist.
那个。。。
也许是这个。如果节点宕机,kubectl/apiserver会出现问题 · Issue #2951 · GoogleCloudPlatform/kubernetes
与CoreOS的对比
ChromeOS自动更新与rpm-ostree有何异同之处?
引用:OSTree:在操作系统镜像和软件包系统之间采取了类似Git的方法,给人一种简洁和灵活性之间的权衡印象。
舰队 vs Kubernetes
原子同捆版本中,fleet更加稳定。Kubernetes有一些漏洞。
因为每天都有发布,所以最新版本可能会更好。
我认为一个相当大的差异是关于主服务器的必要性。
Kubernetes中,如果主服务器崩溃,容器仍然可以运行,但集群管理功能不可用。
而在CoreOS中,所有服务器都处于相同的地位,无论哪个服务器崩溃都不会有任何变化。
我对此的理解是否正确?
然而,Kubernetes具有更丰富的功能。
-
- コンテナ間通信はKubernetesのServiceで実現
-
- Heapsterでクラスタ内コンテナのリソース監視
- fluentd+Elasticsearch+Kibanaによるログ収集・分析
驾驶舱
Cockpit功能在CoreOS中是不可用的。
虽然我们不清楚有多少需求是在一个节点上运行Docker,但如果是这样的话,Cockpit似乎是一个足够好用的工具。它也没有什么问题。
由于Cockpit的0.37版本已经添加了Kubernetes插件,并且还在进一步开发中,所以对于Kubernetes的支持可以期待。(因为我只是试用了Atomic,所以没有尝试最新版本的Cockpit。)
原子的见解
从默认情况下,Kubernetes、etcd和cAdviser都没有启动,只有Docker和Cockpit启动的情况下来看,目前Atomic似乎是作为一台节点上的Docker容器管理主机操作系统而设计的。
目前来看,Docker容器的集群化完全由Kubernetes负责,因此我们只需要安装好Kubernetes,后续可以根据需要自由操作。
总结一下,这个观点是:如果只有一个节点,那么它是可用的(嗯,只是带有Docker的Cockpit),但是集群配置还有很长的路要走。
请看一下
-
- Testing Kubernetes with an Atomic Host — Project Atomic
-
- kubernetes/fedora_manual_config.md at v0.7.0 · GoogleCloudPlatform/kubernetes
-
- kubernetes/README.md at v0.7.0 · GoogleCloudPlatform/kubernetes
- kubernetes/cli.md at release-0.8 · GoogleCloudPlatform/kubernetes