在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》部分。

スクリーンショット 2015-02-16 14.48.44.png

请按常规方式进行启动。
请您在以后组装群集时,为安全组指定一个合适的名称。

スクリーンショット_2015-02-16_14_49_01.png

登录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端口。

スクリーンショット 2015-02-16 15.24.00.png

由于以操作系统的用户账户登录,我们需要为root用户设置密码。

$ sudo passwd root

请访问 http://1.2.3.4:9090

スクリーンショット 2015-02-16 15.30.11.png

使用密码以root用户身份登录后,将显示集群中服务器的列表。

スクリーンショット 2015-02-16 15.40.06.png

您可以监控各资源的使用情况。

スクリーンショット 2015-02-16 15.40.13.png

可以管理Docker容器镜像。

スクリーンショット 2015-02-16 16.08.58.png

Docker容器的管理有许多不同的功能。

启动和停止容器
(很遗憾,无法指定docker run的选项。)

スクリーンショット 2015-02-16 22.42.44.png

为每个容器设置系统资源限制

スクリーンショット 2015-02-16 22.32.49.png

从Docker Hub上拉取镜像

スクリーンショット 2015-02-16 22.38.32.png

除此之外,您还可以通过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。

スクリーンショット 2015-02-23 1.32.03.png

您可以查看服务器资源和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通信。

スクリーンショット 2015-02-17 14.18.14.png

设置主节点

将之前启动的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应用程序从从服务器读取数据,将数据写入主服务器。

由于本次测试只使用两个小黄人,因此前端也将减少到两个。以下是配置的样式。

スクリーンショット 2015-02-26 11.17.30.png

发布 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端口。)

スクリーンショット 2015-02-17 23.06.07.png

尝试自动故障转移

试着停止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
广告
将在 10 秒后关闭
bannerAds