Kubernetes Cookbook 编程指南 中文版教程
创建时间:2018-12-07  访问量:3673  7  0

Kubernetes Cookbook 编程指南 中文版教程

为了达到在AWS OpsWorks中快速部署,我们可以在Chef recipes中写一个安装过装。Chef是基于Ruby的,自动部署管理工具(https://www.chef.io)。它可以帮助程序部署和系统配置。在本节,我们将向你显示Chef是如何与AWS OpsWorks 一起工作的。

开始

在下面的部分中,我们将将你展示如何将Chef recipes与OpsWorks栈一起使用。因此,请准备OpsWorks环境。基于本章前面一节,我们可以使用下面的结构构建一个Kubernetes栈:

让我们考虑您在AWS中构建Kubernetes基础架构这一节中提到了相同的网络设置,这意味着VPC,子网,路由表和安全组都可以使用了。 然后,我们就可以直接在OpsWorks中应用网络环境。

AWS区域对资源集来说应该是一样

尽管OpsWorks是一个全局的服务,我们不可以连接跨不同区域的计算资源。意识到你需要选择相同网络环境的AWS区域来创建ELB和安全组。

创建ELB和它的安全组

正如你在前面栈结构中所看到的,建义在etcd和Kubernetes master之外创建ELB。因为etcd与master节点都可以属于一个多节点的集群,一个ELB层将为其它应用层和工作节点负载均衡的入口。首先,创建这两个ELB的安全组:

Rule name Inbound Protocol and port number Source
My ELB of etcd SG f 80/tcp f My Kubernetes master f My Kubernetes node
My ELB of Kubernetes master SG f 8080/tcp f My Kubernetes node SG

然后,我们可以创建具有特定安全组的ELB。打开EC2控制台并单击左边菜单中的Load balancers。新建一个ELB,配置如下:

ELB name VPC Listener Configuration (ELB Protocol:Port/ Instance Protocol: Port) Subnets Security Groups Health check (Ping Protocol:Ping Port/Ping Path)
my etcd elb My Kubernetes VPC (10.0.0.0/16) HTTP:80/ HTTP:4001 My Kubernetes Private A + My Kubernetes Private D My ELB of etcd SG HTTP:4001/ version
my-k8s master elb HTTP:8080/ HTTP:8080 My ELB of Kubernetes master SG HTTP:8080/ version HTTP:8080/ version

除了上述配置之外,其它项保持黙认即可。你不需要在ELB中添加任何实例。

创建一个OpsWorks栈

在OpsWorks中定义一个应用程序栈是简单容易的。详细参考以下步骤:

  1. 单击Add stack按钮,进入AWS OpsWorks控制台

  2. 为栈设置一个名称。例如,My Kubernetes Cluster

  3. 分配区域和仅仅配置Kubernetes的VPC。

  4. 对于操作系统,Linux系统,最好是下面要安装的最新的Amazon Linux。例如,Amazon Linux2015.09

  5. 单击配置下方的 Advanced>> 并禁用Use OpsWorks security groups块。因为我们已经准备好建立需要的安全组了,这个操作可以减少自动创建许多不必要的安全组。

  1. 现在,继续单击Add stack创建一个Kubernetes栈。

创建一个应用层

有了OpsWorks栈后,我们就可以创建应用层和附属的ELB:

为了在栈中创建一个层,单击栈前面的页面上的 Add a layer 链接:

在创建的第一步,我们不能将ELB附加了层上。在创建它们之后,单击Network修改指定的层。自行生成以下这些层:

Layer Name Short Name (the name as the prefix of instance) Security Group Attached ELB
Etcd etcd My etcd SG my-etcd-elb
Kubernetes Master k8s-master My Kubernetes master SG My flannel SG (optional) my-k8s-master-elb
Kubernetes Node k8s-node My Kubernetes node SG My flannel SG  

实现的栈看起来如下所示,它与我们一开始提到的结构是一样的:

现在,OpsWorks栈有一个基本系统结构,但是没有自定义Chef recipes。我们将在下一节浏览recipe的内容与设置概念。

如何去做...

使用Chef recipe安装Kubernetes,准备一个GitHub仓库,使用下面的文件和相关的路径:

$ tree .
.
└── kubernetes
    ├── recipes
    │ 	├── docker.rb
    │ 	├── etcd-run.rb
    │ 	├── etcd.rb
    │ 	├── flanneld.rb
    │ 	├── kubernetes-master-run.rb
    │ 	├── kubernetes-master-setup.rb
    │ 	├── kubernetes-node-run.rb
    │ 	├── kubernetes-node-setup.rb
    │ 	└── kubernetes.rb
    └── templates
        └── default
            ├── docker.erb
            ├── etcd.erb
            ├── flanneld.erb
            ├── kubernetes-master.erb
            └── kubernetes-node.erb
4 directories, 14 files

本节,使用不同的层来分别而非一起说明recipes和模板。先在GitHub服务器上创建仓库和目录。它将帮助你设置自定义栈配置。

自定义recipes的栈配置

为了在栈中运行recipes,我们假定在栈的配置文件中添加了这两项:一个是GitHub仓库的URL,存储recipe的路径是kubernetes,另一个是自定义JSON。我们在执行recipes时可以放置一些输入参数。

为了修改当前栈的配置,单击主页上的Stack Settings,然后再单击Edit。启用Use custom Chef Cookbooks。你将会发现在基础代码配置上显示了附加项。然后,设置你引用的GitHub仓库URL:

你也可以通过GitHub仓库查看更多信息https://github.com/kubernetes-cookbook/opsworks-recipes.git

下一步,在Advanced options块中,请以Custom JSON项中输入以下信息:

{
    "kubernetes": {
        "version":"1.1.8",
        "cluster_cidr":"192.168.0.0/16",
        "master_url":"<The DNS name of my-k8s-master-elb>"
    },
    "etcd": {
    	"elb_url":"<The DNS name of my-etcd-elb>"
    }
}

JSON的内容是基于Chef recipes的。用户可以定义任何key-value结构的数据。通常情况下,我们设置的这个可能通过每个部署自动改变,例如,Kubernetes软件包的版本。最好不要在recipes中使用硬编码,或者是你不想在recipes中显示的数据,都可以作为输入参数。例如,ELB的URL;对于每个部署(deployment)它都是可变的。你可能不希望其他人知道。配置GitHub仓库和自定义JSON之后,我们就可以每个层中配置recipes了。

Recipes for etcd

etcd层的生命周期事件如下:

我们将etcd recipes的功能分成两个事件阶段:kubernetes::etcd是在etcd安装和配置的Setup阶段设置的,而kubernetes::etcd-run是在Deploy阶段设置以启动守护进程:

$ cat ./kubernetes/recipes/etcd.rb
bash 'install_etcd' do
    user 'root'
    cwd '/tmp'
    code <<-EOH
    if [ ! -f /usr/local/bin/etcd ]; then
        wget --max-redirect 255 https://github.com/coreos/etcd/releases/download/v2.2.5/etcd-v2.2.5-linux-amd64.tar.gz
        tar zxvf etcd-v2.2.5-linux-amd64.tar.gz
        cd etcd-v2.1.1-linux-amd64
        cp etcd etcdctl /usr/local/bin
    fi
    EOH
end

template "/etc/init.d/etcd" do
    mode "0755"
    owner "root"
    source "etcd.erb"
end

首先安装这个etcd.rb的recipe。它把tar包放在临时位置并将二进制文件复制为共享本地命令。为了阻止实例从已准备好安装的环境中启动,我们将添加if语句来检查系统是否有etcd命令。有一个etcd.erb模板,它可作为服务的配置文件。在这个Chef模板中不需要动态输入参数。它与第1章构建你自己的Kubernetes,构建数据存储库这一节提到的是相同的:

$ cat ./kubernetes/recipes/etcd-run.rb
service 'etcd' do
action [:enable,:start]
end

在etcd-run.rb这个recipe中有一个简短的函数,它启用并开启了etcd服务。在Setup阶段之后直接运行Deploy阶段。因此,确认安装要在启动服务之前完成。

Kubernetes Master的Recipes

已经配置了安装Kubernetes Master的recipes,如下截图所示:

就像etcd层一样,我们使用Setup阶段来安装和分配配置文件。这个kubernetes::kubernetes Recipe用来下载Kubernetes软件包。它也会与Node层共享:

$ cat ./kubernetes/recipes/kubernetes.rb
bash 'install_kubernetes' do
    user 'root'
    cwd '/tmp'
    code <<-EOH
    if [[ $(ls /usr/local/bin/kubectl) ]]; then
   		current_version=$(/usr/local/bin/kubectl version | awk 'NR==1' | awk -F":\"v" '{ print $2 }' | awk -F"\"," '{ print $1 }')
    	if [ "$current_version" -eq "#{node['kubernetes']['version']}" ];
        then
            exit
    	fi
	fi

    if [[ $(ls /usr/local/bin/kubelet) ]] ; then
        current_version=$(/usr/local/bin/kubelet --version | awk -F"Kubernetes v" '{ print $2 }')
        if [ "$current_version" -eq "#{node['kubernetes']['version']}" ];
        then
            exit
        fi
    fi
    
    rm -rf kubernetes/
    wget --max-redirect 255 https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v#{node['kubernetes']['version']}/kubernetes.tar.gz -O kubernetes-#{node['kubernetes']['version']}.tar.gz
    tar zxvf kubernetes-#{node['kubernetes']['version']}.tar.gz
    cd kubernetes/server
    tar zxvf kubernetes-server-linux-amd64.tar.gz
    EOH
end

在本节,Kubernetes版本值是从自定义JSON中获取的。我们可以指定最新Kubernetes的版本并在不改动recipe前提下享有最新的功能。两个嵌套的if条件用来验证Kubernetes二进制文件是否已经部署并更新到我们要求的版本。一个是Master上的,另一个是Node上的;如果条件满足,会忽略软件包的下载。Kubernetes Master的主安装写在了kubernetes-master-setup.rb这个recipe中:

$ cat ./kubernetes/recipes/kubernetes-master-setup.rb
include_recipe 'kubernetes::kubernetes'

bash "master-file-copy" do
    user 'root'
    cwd '/tmp/kubernetes/server/kubernetes/server/bin'
    code <<-EOH
    if [[ $(ls /usr/local/bin/kubectl) ]]; then
        current_version=$(/usr/local/bin/kubectl version | awk 'NR==1' | awk -F":\"v" '{ print $2 }' | awk -F"\"," '{ print $1 }')
        if [ "$current_version" -eq "#{node['kubernetes']['version']}" ];then
        	exit
        fi
    fi
        cp kubectl kube-apiserver kube-scheduler kube-controller-manager kube-proxy /usr/local/bin/
    EOH
end

directory '/etc/kubernetes' do
    owner 'root'
    group 'root'
    mode '0755'
    subscribes :create, "bash[master-file-copy]", :immediately
    action :nothing
end

etcd_endpoint="http://#{node['etcd']['elb_url']}:80"

template "/etc/init.d/kubernetes-master" do
    mode "0755"
    owner "root"
    source "kubernetes-master.erb"
    variables({
        :etcd_server => etcd_endpoint,
        :cluster_cidr => node['kubernetes']['cluster_cidr']
    })
    subscribes :create, "bash[master-file-copy]", :immediately
    	action :nothing
end

kubernetes-master-setup.rb的第一行的设置是解决在相同事件阶段上的依赖的。资源类型include_recipe需要你先执行kubernetes::kubernetes这个recipe。然后,如果验证条件版本中的进程不存在,它会复制必要的二进制文件,再为服务准备合适的配置文件和目录。

在Master节点安装flanneld是可选的部署。如果这样做,那么在Kubernetes Master节点上,我们可以依赖flanneld来访问容器:

$ cat ./kubernetes/recipes/flanneld.rb
bash 'install_flannel' do
    user 'root'
    cwd '/tmp'
    code <<-EOH
    if [ ! -f /usr/local/bin/flanneld ]; then
        wget --max-redirect 255 https://github.com/coreos/flannel/releases/download/v0.5.2/flannel-0.5.2-linux-amd64.tar.gz
        tar zxvf flannel-0.5.2-linux-amd64.tar.gz
        cd flannel-0.5.2
        cp flanneld /usr/local/bin
        cp mk-docker-opts.sh /opt/
    fi
    EOH
end

template "/etc/init.d/flanneld" do
    mode "0755"
    owner "root"
    source "flanneld.erb"
    variables :elb_url => node['etcd']['elb_url']
    notifies :disable, 'service[flanneld]', :delayed
end

service "flanneld" do
	action :nothing
end

特别的,我们将flanneld的脚本文件移动到指定的路径中。这个文件帮助调整flanneld-defined的网络。因此,Docker将基于这个设置来限制指定IP范围内的容器。对于模板,etcd端点的值是recipe的一个输入参数。这个recipe将告诉模板将ELB URL作为一个etcd端点来放置:

$ cat ./kubernetes/templates/default/flanneld.erb
:
//above lines are ignored
start() {
    # Start daemon.
    echo -n $"Starting $prog: "
    daemon $prog \
        --etcd-endpoints=http://<%= @elb_url %> -ip-masq=true \
        > /var/log/flanneld.log 2>&1 &
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch $lockfile
    return $RETVAL
} 
:

最后,我们最好看一下启动服务的recipe:

$ cat ./kubernetes/recipes/kubernetes-master-run.rb
service "flanneld" do
	action :start
end

service "kubernetes-master" do
	action :start
end

在这个recipe中,它直接启动这两个独立的守护进程。

Kubernetes Node的Recipes

根据前面的经验,现可以很容易的理解自定义recipes和Chef功能的部署了。然后,我们将进一步查看Kubernetes Node层的recipes:

除了flanneld之外,我们需要为运行的容器安装Docker。然而,要在Setup阶段放置一个附加的kubernetes::docker recipe。

$ cat ./kubernetes/recipes/docker.rb
package "docker" do
	action :install
end

package "bridge-utils" do
	action :install
end

service "docker" do
	action :disable
end

template "/etc/sysconfig/docker" do
    mode "0644"
    owner "root"
    source "docker.erb"
end

在本节中,我们将安装docker和bridge-utils这两必要的软件包。但是要保持Docker服务处于停止状态,因为存在一个服务启动的依赖:

$ cat ./kubernetes/templates/default/docker.erb
# /etc/sysconfig/docker
#
# Other arguments to pass to the docker daemon process
# These will be parsed by the sysv initscript and appended
# to the arguments list passed to docker -d

. /opt/mk-docker-opts.sh
. /run/docker_opts.env

INSECURE_REGISTRY="<YOUR_DOCKER_PRIVATE_REGISTRY>"
other_args="${DOCKER_OPTS} --insecure-registry ${INSECURE_REGISTRY}"
DOCKER_CERT_PATH=/etc/docker

# Location used for temporary files, such as those created by
# docker load and build operations. Default is /var/lib/docker/tmp
# Can be overriden by setting the following environment variable.
# DOCKER_TMPDIR=/var/tmp

前面模板的调用使用了docker.rb。尽管没有输入参数,但值得一提的是,flanneld的脚本将被触发运行。它将为Docker生成一个网络设置并放在/run/docker_opts.evn文件中。

接下来,你将发现Node的setup recipe与Master的相似。我们复制二进制文件、安装配置文件和目录,并保持Node服务处于停止状态:

$ cat ./kubernetes/recipes/kubernetes-node-setup.rb
include_recipe 'kubernetes::kubernetes'

bash "node-file-copy" do
    user 'root'
    cwd '/tmp/kubernetes/server/kubernetes/server/bin'
    code <<-EOH
    if [[ $(ls /usr/local/bin/kubelet) ]]; then
        current_version=$(/usr/local/bin/kubelet --version | awk -F"Kubernetes v" '{ print $2 }')
        if [ "$current_version" -eq "#{node['kubernetes']['version']}" ]; then
        	exit
        fi
    fi
    cp kubelet kube-proxy /usr/local/bin/
    EOH
end

directory '/var/lib/kubelet' do
    owner 'root'
    group 'root'
    mode '0755'
    subscribes :create, "bash[node-file-copy]", :immediately
	action :nothing
end

directory '/etc/kubernetes' do
    owner 'root'
    group 'root'
    mode '0755'
    subscribes :create, "bash[node-file-copy]", :immediately
    action :nothing
end

template "/etc/init.d/kubernetes-node" do
    mode "0755"
    owner "root"
    source "kubernetes-node.erb"
    variables :master_url => node['kubernetes']['master_url']
    subscribes :create, "bash[node-file-copy]", :immediately
    notifies :disable, 'service[kubernetes-node]', :delayed
     action :nothing
end

service "kubernetes-node" do
	action :nothing
end

另一方面,Node的部署recipe有更多的功能:

$ cat ./kubernetes/recipes/kubernetes-node-run.rb
service "flanneld" do
	action :start
	notifies :run, 'bash[wait_flanneld]', :delayed
end

bash 'wait_flanneld' do
	user 'root'
	cwd '/tmp'
	code <<-EOH
    tries=0
        while [ ! -f /run/flannel/subnet.env -a $tries -lt 10 ]; do
            sleep 1
            tries=$((tries + 1))
        done
    EOH
    action :nothing
	notifies :start, 'service[docker]', :delayed
end

service "docker" do
    action :nothing
    notifies :start, 'service[kubernetes-node]', :delayed
end

service "kubernetes-node" do
	action :nothing
end

由于依赖,应该先启动flanneld,然后Docker可以根据层叠网络运行。Node服务依赖于运行的Docker,因此,它是最后一个需要启动的服务。

启动一个实例

最后,你有了准备部署一个Kubernetes集群的所有Recipes。是时候启动一些实例了!确保etcd实例是最先启动的。那时,Kubernetes Master层就可以运行Master了,它需要为资源信息提供存储库。在Master节点也准备好之后,你想创建多少Node就可以创建多少Node!

也可以参考

本节,你学习了如何自动创建你的Kubernetes系统。也可以查看以下章节:

  • 第1章构建你自己的Kubernetes,构建数据存储库,创建一个层叠网络,配置Master和Node这几节

  • 第4章构建一个高可用集群,etcd集群这一节

  • 在AWS上构建Kubernetes基础设施

  • 使用AWS OpsWorks管理应用

  • 使用AWS CloudFormation快速供给

  • 第7章高级集群管理,授权与认证这一节