一 Kubernetes介绍
1.Kubernetes是什么
Kubernetes是一个用于在由多个主机组成的集群上对应用容器自动化部署,扩容和运维的开源平台,它提供一个以容器为中心的基础设施。
利用Kubernetes,你可以快速和有效地响应客户需求:
-- 快速地和可预期地部署应用
-- 动态地(on the fly)扩展应用
-- 无缝地升级新特性
-- 按需使用硬件资源,提升硬件资源利用率
2.为什么使用容器
部署应用的老方法是使用操作系统的包管理工具(rpm,deb)在一台主机上安装应用。
这样做有个缺点,应用的执行文件,配置文件,库文件以及各自的生命周期容易与主机操作系统混在一起。你可以使用不经常变动的虚拟机镜像来达到可预期地向前升级和向后回滚的目的,但是虚拟机比较笨重和不可移植。
新方法是基于操作系统级别的虚拟化而不是硬件虚拟化来部署容器。这些容器彼此相互隔离,它们有各自的文件系统,他们不能看到彼此的进程,它们的计算资源使用可以绑定。它们比虚拟机更容易构建,因为它们和下行的基础设施解耦,从宿主机操作系统层面来看,它们可以移植到不同云端和操作系统分支。
因为容器小而快,一个应用可以被打包在各自的容器镜像中。
使用的容器的益处总结:
-- 灵活地创建和部署应用
-- 持续开发,集成和部署
-- 创建应用容器在构建和发布上消耗时间而不是在部署上消耗时间,与基础架构解耦
-- 开发环境,测试环境和线上环境的环境变量保持一致。在笔记本上和云端一样运行
-- 在各种云端和操作系统分支上可移植
-- 基于应用中心管理
-- 资源隔离
-- 提高资源利用率
3.为什么需要Kubernetes以及能够利用它做什么
最起码,Kubernetes能够在由多个物理主机或者虚拟机组成的集群上调度和运行应用容器。
Kubernetes满足一系列生产环境中运行应用的需求:
-- co-locating helper processes
-- mounting storage systems
-- distributing secrets
-- application health checking
-- replicating application instances
-- horizontal auto-scaling
-- naming and discovery
-- load blancing
-- rolling updates
-- resource monitoring
-- log access and ingestion
-- support for introspection and debugging
-- identify and authorization
4.为什么Kubernetes是一个平台以及Kubernetes如何成为一个平台
即使Kubernetes提供了很多功能,总有需要从新特性中受益的应用场景。面向应用的工作流可以加快开发速度。
Kubernetes的Labels可以允许用户根据需要组织资源。Annotations运行用户标注资源。另外,Kubernetes控制面板是使用同开发者和用户相同的API。
Kubernetes不是:
Kubernetes不是一个传统的,所有都包含的PaaS(平台即服务)的系统。
-- Kubernetes不限制应用类型。
-- Kubernetes本身不自带中间件服务(比如消息系统),数据处理框架(比如Spark),数据库服务(比如mysql),也不提供集群存储服务(比如Ceph)。这些应用都是运行在Kubernetes上的
-- Kubernetes does not have a click-to-deploy service marketplace
-- Kubernetes is unopinionated in the source-to-p_w_picpath space.
-- Kubernetes允许用户自行选择如何打印日志,监控以及报警
-- Kubernetes不提供也不托管复杂的应用配置语言或系统
-- kubernetes不提供也不采用任何复杂的机器配置,维护,管理或者自愈的系统
由于Kubernetes运行在应用级别而不是硬件级别,它提供一些PaaS具有的通用应用特性,比如部署,扩展,负载均衡,打印日志,监控等等。
此外,Kubernetes不只是一个"Orchestration system"(编排系统).它减少了编排的需求。术语orchestration(编排)的定义就是执行一个预先定义好的执行过程:执行A,然后执行B,然后执行C。相反地,Kubernetes是由一系列独立的,可组和的控制进程组成来持续驱动当前状态到提供的期望状态。它不需要关心如何从A达到C。
二 安装并使用Kubernetes
1.创建Kubernetes集群
Kubernetes官网列出了很多部署Kubernetes集群的方案,本文只讨论如何在CentOS7上部署Kubernetes集群
在CentOS有两种方式可以创建Kubernetes集群:
a.从源码包自定义安装各个组件然后手动创建
b.使用yum源安装各个组件然后启动服务
a.从源码包自定义安装各个组件然后手动创建
使用源码包自定义创建集群有点麻烦,官方建议是先使用yum源直接创建好,对Kubernetes有一定理解过后再根据自己需要自定义创建集群
本文使用CentOS7来测试Kubernetes,Docker使用https://yum.dockerproject.org/repo/main/centos/7/Packages/ 提供的最新版本
CentOS7升级操作系统内核到4.7.1 ,CentOS7默认的内核运行Docker可能会崩溃
参考文档 http://dl528888.blog.51cto.com/2382721/1655142
vim /etc/yum.repos.d/docker.repo
[dockerrepo] name=Docker Repository baseurl=https://yum.dockerproject.org/repo/main/centos/7/ enabled=1 gpgcheck=1 gpgkey=https://yum.dockerproject.org/gpg
sudo yum install docker-engine net-tools -y
service docker start
chkconfig docker on
下载最新版本的kubernetes
wget https://github.com/kubernetes/kubernetes/releases/download/v1.3.5/kubernetes.tar.gz tar zxvf kubernetes.tar.gz cd kubernetes/server/ tar zxvf kubernetes-server-linux-amd64.tar.gz
在Kubernetes上部署和管理应用是通过命令行工具kubectl
cp kubernetes/platforms/linux/amd64/kubectl /opt/app/kubernetes/sbin cp server/kubernetes/server/bin/kubelet /opt/app/kubernetes/sbin/ cp server/kubernetes/server/bin/kube-proxy /opt/app/kubernetes/sbin/ cp server/kubernetes/server/bin/kube-apiserver /opt/app/kubernetes/sbin/ cp server/kubernetes/server/bin/kube-controller-manager /opt/app/kubernetes/sbin/ cp server/kubernetes/server/bin/kube-scheduler /opt/app/kubernetes/sbin/ chmod a+x /opt/app/kubernetes/sbin/* export PATH=$PATH:/opt/app/kubernetes/sbin
安装路径自己随意定
需要两台CentOS7主机
这里先只部署一个集群节点工作,多节点需要在外部配置网络服务。
kubernetes安装包提供了好几个服务:kube-apiserver,kube-scheduler,kube-controller-manager,kubelet,kube-proxy
创建一个Kubernetes集群需要以下二进制执行文件:
etcd
docker或者rkt
kubelet
kube-proxy
kube-apiserver
kube-controller-manager
kube-scheduler
将docker,kubelet,kube-proxy在容器外运行,etcd,kube-apiserver,kube-controller-manager,kube-scheduler建议以容器的方式运行,所以需要由一个镜像来构建
Kubernetes安装包包含有相关的镜像,位于kubernetes/server/kubernetes/server/bin目录下
docker load -i kube-apiserver.tar docker load -i kube-scheduler.tar docker load -i kube-controller-manager.tar
对于etcd,官方建议使用kubernetes安装包自带的版本,因为这个版本和kubernetes经过了严格的测试。
建议的版本可以在kubernetes/cluster/p_w_picpaths/etcd/Makefile文件中的TAG参数看到,目前是2.2.5
构建etcd镜像
cd kubernetes/cluster/p_w_picpaths/etcd/;make
安全模型
有两个选择:
使用HTTP访问apiserver,使用防火墙添加安全策略,比较容易设置
使用HTTPS访问apiserver,为用户添加认证和证书,这是建议的方式,配置证书有点麻烦
Authenticating 认证
所有的Kubernetes集群有两类用户:由kubernetes管理的服务账号和普通用户
Preparing Certs
-- master需要一个cert来作为一个HTTPS服务器
-- kubelets可选择性需要certs来表明它们是master的客户端,通过HTTPS提供自己的API服务业需要certs
最终有以下几个文件(以下用变量表示):
CA_CERT
放到apiserver运行的节点上,例如/srv/kubernetes/ca.crt
MASTER_CERT
放到apiserver运行的节点上,例如/srv/kubernetes/server.crt
MASTER_KEY
放到apiserver运行的节点上,例如/srv/kubernetes/server.key
KUBELET_CERT
可选
KUBELET_KEY
可选
有三种方法可以制作证书
使用自带的脚本制作证书
脚本路径位于kubernetes/server/kubernetes/cluster/saltbase/salt/generate-cert/make-ca-cert.sh
sh make-ca-cert.sh 172.xxx.xxx.xxx IP就是apiserver的IP
脚本执行成功后会在/srv/kubernetes/ 目录下生成ca.crt,server.cert,server.key,kubecfg.crt,kubecfg.key几个文件
最后在apiserver启动的时候需要添加以下几个参数
--client-ca-file=/srv/kubernetes/ca.crt
--tls-cert-file=/srv/kubernetes/server.cert
--tls-private-key-file=/srv/kubernetes/server.key
使用easyrsa制作证书
curl -L -O https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz tar xzf easy-rsa.tar.gz cd easy-rsa-master/easyrsa3 ./easyrsa init-pki ./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass ./easyrsa --subject-alt-name="IP:${MASTER_IP}" build-server-full kubernetes-master nopass
将pki/ca.crt
, pki/issued/kubernetes-master.crt
,pki/private/kubernetes-master.key 几个文件复制到自己的目录
最后为apiserver添加几个启动参数
--client-ca-file=/yourdirectory/ca.crt --tls-cert-file=/yourdirectory/server.cert --tls-private-key-file=/yourdirectory/server.key
使用openssl制作证书
openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt openssl genrsa -out server.key 2048 openssl req -new -key server.key -subj "/CN=${MASTER_IP}" -out server.csr openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 10000 openssl x509 -noout -text -in ./server.crt
同样为apiserver添加几个启动参数
--client-ca-file=/yourdirectory/ca.crt --tls-cert-file=/yourdirectory/server.cert --tls-private-key-file=/yourdirectory/server.key
Preparing Credentials
管理员用户和其他任何用户需要:
一个token或者一个密码来识别身份
tokens仅仅只是一长串由字母和数字组成的字符串,例如
TOKEN=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64 | tr -d "=+/" | dd bs=32 count=1 2>/dev/null)
密码和tokens需要存储在一个文件中便于apiserver查看,使用 --token-auth-file=/var/lib/kube-apiserver/known_tokens.csv 这样指定文件,token文件实际上是一个csv文件,包含有至少三列:token,user,uid,"group1,group2,group3"
为了将证书分发到客户端,kubernetes约定的方法是将证书放到kubeconfig文件中
/opt/app/kubernetes/sbin/kubectl config set-cluster k8stest --certificate-authority=/srv/kubernetes/ca.crt --embed-certs=true --server=https://172.30.xx.xx
b.使用yum源安装各个组件然后启动服务
准备两台安装有CentOS7的物理机或者虚拟机
在/etc/hosts文件中添加
172.30.30.215 centos-master 172.30.30.216 centos-minion
添加yum源/etc/yum.repos.d/virt7-docker-common-release.repo
[virt7-docker-common-release] name=virt7-docker-common-release baseurl=http://cbs.centos.org/repos/virt7-docker-common-release/x86_64/os/ gpgcheck=0
安装kubernetes,etcd,docker
yum -y install --enablerepo=virt7-docker-common-release kubernetes etcd
修改/etc/kubernetes/config
#Comma separated list of nodes in the etcd cluster KUBE_ETCD_SERVERS="--etcd-server=http://centos-master:2379" # 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 privileged docker containers KUBE_ALLOW_PRIV="--allow-privileged=false" # How the controller-manager, scheduler, and proxy find the apiserver KUBE_MASTER="--master=http://centos-master:8080"
两台主机上都关闭iptables
systemctl disable iptables-services firewalld systemctl stop iptables-services firewalld
在master端配置kubernetes服务
编辑/etc/etcd/etcd.conf
# [member] ETCD_NAME=default ETCD_DATA_DIR="/var/lib/etcd/default.etcd" ETCD_LISTEN_CLIENT_URLS=" #[cluster] ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379"
编辑/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" # Port minions listen on KUBELET_PORT="--kubelet-port=10250" # Comma separated list of nodes in the etcd cluster KUBE_ETCD_SERVERS="--etcd-servers=http://0.0.0.0:2379" # Address range to use for services KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16" # default admission control policies KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota" # Add your own! KUBE_API_ARGS=""
在master端启动服务
for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler; do systemctl restart $SERVICES systemctl enable $SERVICES systemctl status $SERVICES done
在kubernetes节点上配置服务
编辑/etc/kubernetes/kubelet
# The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces) 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=centos-minion" # location of the api-server KUBELET_API_SERVER="--api-servers=http://centos-master:8080" # pod infrastructure container KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-p_w_picpath=registry.access.redhat.com/rhel7/pod-infrastructure:latest" # Add your own! KUBELET_ARGS=""
在节点上启动服务
for SERVICES in kube-proxy kubelet docker; do systemctl restart $SERVICES systemctl enable $SERVICES systemctl status $SERVICES done
2.了解Kubectl命令行工具和Kubernetes的Pods
Pods
在Kubernetes中,一组单个或者多个容器叫做一个Pod。同一个Pod中的容器一起部署,以一个组的方式启动,停止和复制
Pod Definition
最简单的Pod定义就是描述部署单个容器。比如pod-nginx.yaml部署一个nginx web容器
apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx p_w_picpath: nginx:1.7.9 ports: - containerPort: 80
一个pod定义就是一个期望状态desired state的声明。Desired state在Kubernetes模型中是一个非常重要的概念。许多东西都会对系统呈现一个期望状态,Kubernetes的责任就是将当前状态匹配到期望状态。例如,当创建一个Pod,就声明想要这个Pod中的容器可以正常运行。如果这些容器碰巧没有运行(比如程序执行失败),Kubernetes将继续重建它们驱使达到期望状态,直到这个Pod被删除。
Pod Management
#kubectl create -f pod-nginx.yaml
# kubectl get pod nginx NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 3h
执行的过程中可能会报错
pods "nginx" is forbidden: no API token found for service account default/default, retry after the token is automatically created and added to the service account
解决办法:
将/etc/kubernetes/apiserver文件中的
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"
修改成
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"
多数情况下,pod的IP对外是不可见的。测试pod是否工作的最简单的方法就是创建一个busybox pod然后远程在它上面执行命令。
Kubernetes通过环境变量暴露服务,可以使用kubectl exec查看这些环境变量
# kubectl exec nginx env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=nginx KUBERNETES_SERVICE_PORT=443 KUBERNETES_SERVICE_PORT_HTTPS=443 KUBERNETES_PORT=tcp://10.254.0.1:443 KUBERNETES_PORT_443_TCP=tcp://10.254.0.1:443 KUBERNETES_PORT_443_TCP_PROTO=tcp KUBERNETES_PORT_443_TCP_PORT=443 KUBERNETES_PORT_443_TCP_ADDR=10.254.0.1 KUBERNETES_SERVICE_HOST=10.254.0.1 NGINX_VERSION=1.7.9-1~wheezy HOME=/root
根据pod名字删除pod
# kubectl delete pod nginx
Volumes
容器的文件系统会随着容器关闭而销毁,如果需要持久化保持数据就需要配置持久化存储。
以下pod-redis.yaml定义一个redis pod
apiVersion: v1 kind: Pod metadata: name: redis spec: containers: - name: redis p_w_picpath: redis volumeMounts: - name: redis-persistent-storage mountPath: /data/redis volumes: - name: redis-persistent-storage emptyDir: {}
Multiple Containers
以下配置只是语法正确,不能使用
apiVersion: v1 kind: Pod metadata: name: www spec: containers: - name: nginx p_w_picpath: nginx volumeMounts: - mountPath: /srv/www name: www-data readOnly: true - name: git-monitor p_w_picpath: kubernetes/git-monitor env: - name: GIT_REPO value: http://github.com/some/repo.git volumeMounts: - mountPath: /data name: www-data volumes: - name: www-data emptyDir: {}
Labels,Deployments,Services and Health Checking
Kubernetes的labels就是将很多个pods进行分组。
prod-nginx-with-label.yaml
apiVersion: v1 kind: Pod metadata: name: nginx labels: app: nginx spec: containers: - name: nginx p_w_picpath: nginx ports: - containerPort: 80
#kubectl create -f pod-nginx-with-label.yaml
列出所有标签是app=nginx的pods
#kubectl get pods -l app=nginx
Deployments
使用deployment来管理和更新运行的pods
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 2 #tells deployment to run 2 pods matching the template template: # create pods using pod definiton in this template metadata: labels: app: nginx spec: containers: - name: nginx p_w_picpath: nginx:1.7.9 ports: - containerPort: 80
kubectl create -f deployment.yaml
列出所有的deployment
kubectl get deployment
列出deloyment创建的pods
# kubectl get pods -l app=nginx NAME READY STATUS RESTARTS AGE nginx-deployment-2035384211-6ml5p 1/1 Running 0 11m nginx-deployment-2035384211-cd9p4 1/1 Running 0 11m
将nginx容器从1.7.9升级到1.8
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 2 #tells deployment to run 2 pods matching the template template: # create pods using pod definiton in this template metadata: labels: app: nginx spec: containers: - name: nginx p_w_picpath: nginx:1.8 ports: - containerPort: 80
kubectl apply -f deployment-update.yaml
kubernetes会先下载新的docker镜像然后创建pods,最后会删除老的pods
删除deployment
kubectl delete deployment nginx-deployment
Services
service.yaml
apiVersion: v1 kind: Service metadata: name: nginx-service spec: ports: - port: 8000 # the port that this service should serve on # the container on each pod to connect to,can be a name # (e.g. 'www') or a number (e.g 80) targetPort: 80 protocol: TCP # just like the selector in the deployment, # but this time it identifies the set of pods to load balance # traffic to selector: app: nginx
创建一个nginx service
kubectl create -f service.yaml
获取所有的services
kubectl get services
大多数情况下,服务IP对外不可访问,可以通过以下方式测试
$ export SERVICE_IP=$(kubectl get service nginx-service -o go-template='``.`spec`.`clusterIP`') $ export SERVICE_PORT=$(kubectl get service nginx-service -o go-template='{{(index .spec.ports 0).port}}') $ echo "$SERVICE_IP:$SERVICE_PORT" $ kubectl run busybox --generator=run-pod/v1 --p_w_picpath=busybox --restart=Never --tty -i --env "SERVICE_IP=$SERVICE_IP,SERVICE_PORT=$SERVICE_PORT" u@busybox$ wget -qO- http://$SERVICE_IP:$SERVICE_PORT # Run in the busybox container u@busybox$ exit # Exit the busybox container $ kubectl delete pod busybox # Clean up the pod we created with "kubectl run"
删除service
kubectl delete service nginx-service
每个service被创建的时候都会分配一个唯一的IP地址,这个IP地址会和这个service的整个生命周期关联。service是存活的时候,它的IP地址不会更改。
Health Checking
Process Health Checking
健康检查最简单的形式就是只做进程级别的健康检查。Kubelet会持续询问Docker后台进程容器是否让然在运行,如果没有在运行,这个容器进程会被重启。
Application Health Checking
在很多应用场景下低级别的健康检查是不足够的。比如以下的例子:
lockOne := sync.Mutex{} lockTwo := sync.Mutex{} go func() { lockOne.Lock(); lockTwo.Lock(); ...}() lockTwo.Lock(); lockOne.Lock();
这个就是计算机科学中的经典例子,死锁问题。从Docker的角度,应用程序仍然在运作,进程仍然在运行。但是从应用的角度,代码已经锁住,不会再作出响应。
为了找出这个问题,Kubernetes支持用户自定义应用程序级别的健康检查,这些检查通过Kubelet来执行。
目前,有三种类型的应用健康检查:
-- HTTP健康检查
Kubelet调用一个web回调地址,返回码在200到399之间被认为是成功的
-- 容器执行
Kubelet在容器内执行一个命令,如果退出时返回0就认为成功
-- TCP Socket
Kubelet会尝试打开一个socket到容器,如果可以建立连接,那么这个容器就被认为是健康的,如果不是就是失败的
在所有的场景下,Kubelet发现一个错误就是会重启这个容器
容器的健康检查通过容器配置文件中的livenessProbe 指定。initialDelaySeconds 指定容器从启动到初始执行健康检查的间隔时间
prod-with-http-healthcheck.yaml
apiVersion: v1 kind: Pod metadata: name: pod-with-healthcheck spec: containers: - name: nginx p_w_picpath: nginx # defines the health checking livenessProbe: # an http probe httpGet: path: /_status/healthz port: 80 # length of time to wait for a pod to initialize # after pod startup, before applying health checking initialDelaySeconds: 30 timeoutSeconds: 1 ports: - containerPort: 80
3.Kubernetes的WEB界面
4.Workload Deployment and Management
Launching,Exposing,and Killing Applications
kubectl run创建两个nginx副本,监听80端口
# kubectl run my-nginx --p_w_picpath=nginx --replicas=2 --port=80 deployment "my-nginx" created
# kubectl expose deployment my-nginx --target-port=80 --type=LoadBalancer service "my-nginx" exposed
# kubectl get po NAME READY STATUS RESTARTS AGE my-nginx-3800858182-f2y66 1/1 Running 0 5m my-nginx-3800858182-wmby3 1/1 Running 0 5m
Kubernetes将自动重启检测失败的容器,将容器分布到不同的节点,当一个节点检测失败时重新在新的节点上创建容器来确保应用继续运行。
获取应用分配到的公共IP
# kubectl get service my-nginx NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-nginx 10.254.186.253 80/TCP 6m
杀掉应用并删除它的容器和公共IP
# kubectl delete deployment,service my-nginx deployment "my-nginx" deleted service "my-nginx" deleted
Deploying Applications
Kubernetes 使用 deployment 来创建和管理多组容器副本。
run-my-nginx.yaml
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: my-nginx spec: replicas: 2 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx p_w_picpath: nginx ports: - containerPort: 80
# kubectl create -f run-my-nginx.yaml deployment "my-nginx" created
不像直接创建pods的案例,一个Deployment会替换任何原因导致被删除或者终结的pods,比如节点检测失败的情况。基于这个原因,建议为一个持续运行的应用使用一个Deployment即使这个应用只需要一个pod,可以不设置replicas参数,那么创建Deployment的时候会默认创建一个pod。
# kubectl get deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE my-nginx 2 2 2 2 46m
# kubectl get pods NAME READY STATUS RESTARTS AGE my-nginx-3800858182-y6b52 1/1 Running 0 47m my-nginx-3800858182-ytrnu 1/1 Running 0 47m
# kubectl delete deployment/my-nginx deployment "my-nginx" deleted
Labels
Kubernetes 使用用户定义名叫labels的键值属性对资源归类,比如pods和Deployments.
# kubectl get pods -L run NAME READY STATUS RESTARTS AGE RUN my-nginx-3800858182-aw6ni 1/1 Running 0 43s my-nginx my-nginx-3800858182-hlsqx 1/1 Running 0 43s my-nginx
# kubectl get deployment/my-nginx -L run NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE RUN my-nginx 2 2 2 2 10m my-nginx
# kubectl get deployment/my-nginx -o template --template="``.`spec`.`selector`" map[matchLabels:map[run:my-nginx]]
Managing Resources
许多应用在创建时需要多种资源,可以简单地把多种资源在同一个文件中指定
nginx-app.yaml
apiVersion: v1kind: Servicemetadata: name: my-nginx-svc labels: app: nginxspec: type: LoadBalancer ports: - port: 80 selector: app: nginx---apiVersion: extensions/v1beta1kind: Deploymentmetadata: name: my-nginxspec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx p_w_picpath: nginx:1.7.9 ports: - containerPort: 80
# kubectl create -f nginx-app.yaml service "my-nginx-svc" created deployment "my-nginx" created
也可以指定多个文件或者指定目录
#kubectl create -f docs/user-guide/nginx/nginx-svc.yaml -f docs/user-guide/nginx/nginx-deployment.yaml
#kubectl create -f docs/user-guide/nginx/
kubectl 将读取任何以 .yaml, .yml 或者 .json后缀的文件
也可以指定配置文件为一个url
$ kubectl create -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/docs/user-guide/nginx-deployment.yaml deployment "nginx-deployment" created
kubectl不只能批量创建资源,也能从配置文件中解析资源名称
# kubectl delete -f nginx-app.yaml service "my-nginx-svc" deleted deployment "my-nginx" deleted
# kubectl delete deployments/my-nginx services/my-nginx-svc deployment "my-nginx" deleted service "my-nginx-svc" deleted
# kubectl delete deployments,services -l app=nginx deployment "my-nginx" deleted deployment "nginx-deployment" deleted service "my-nginx-svc" deleted
# kubectl get $(kubectl create -f nginx-app.yaml -o name|grep service) NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-nginx-svc 10.254.122.72 80/TCP 0s
--recursive 或者 -R 参数可以跨子目录执行
project/k8s/development ├── configmap │ └── my-configmap.yaml ├── deployment │ └── my-deployment.yaml └── pvc └── my-pvc.yaml
$ kubectl create -f project/k8s/development --recursive configmap "my-config" created deployment "my-deployment" created persistentvolumeclaim "my-pvc" created
--recursive 可以被任何接收 -f 参数的命令使用,例如 kubectl create,get,delete,describe,rollout
$ kubectl create -f project/k8s/namespaces -f project/k8s/development --recursive namespace "development" created namespace "staging" created configmap "my-config" created deployment "my-deployment" created persistentvolumeclaim "my-pvc" created
在许多场景下需要使用多个labels来区分不同的应用或者同一个应用的不同层级。例如https://github.com/kubernetes/kubernetes/tree/master/examples/guestbook/ 中的例子frontend可以这些labels
labels: app: guestbook tier: frontend
Redis master和slave使用不同的tier和role
labels: app: guestbook tier: backend role: master
labels: app: guestbook tier: backend role: slave
# kubectl create -f /opt/software/kubernetes/examples/guestbook/all-in-one/guestbook-all-in-one.yaml service "redis-master" created deployment "redis-master" created service "redis-slave" created deployment "redis-slave" created service "frontend" created deployment "frontend" created # kubectl get pods -L app -L tier -L role NAME READY STATUS RESTARTS AGE APP TIER ROLE frontend-440143558-feyo4 0/1 ContainerCreating 0 3m guestbook frontendfrontend-440143558-l7kb7 0/1 ContainerCreating 0 3m guestbook frontend frontend-440143558-x3in0 0/1 ContainerCreating 0 3m guestbook frontend my-nginx-2035384211-t2trb 1/1 Running 0 21h nginx my-nginx-2035384211-xlgvr 1/1 Running 0 21h nginx my-nginx-2035384211-ykqit 1/1 Running 0 21h nginx pod-with-healthcheck 0/1 Terminating 858 1d redis-master-2353460263-a9jf9 1/1 Running 0 3m redis backend master redis-slave-1691881626-lz1vi 1/1 Running 0 3m redis backend slave redis-slave-1691881626-rzpd0 0/1 ContainerCreating 0 3m redis backend slave
另一个需要使用多标签的场景就是区分相同组件的不同版本的发布或者配置。惯用做法就是和之前的版本一起部署一个新的版本,这样完全切换到新版本之前可以接收生产环境流量。
例如,可以使用一个track标签区分不同的版本
首先,稳定版本使用一个值为stable的track标签
name: frontend replicas: 3 ... labels: app: guestbook tier: frontend track: stable ... p_w_picpath: gb-frontend:v3
然后可以创建一个新版本给track标签一个不同的值,这样两组pods就不会重叠:
name: frontend-canary replicas: 1 ... labels: app: guestbook tier: frontend track: canary ... p_w_picpath: gb-frontend:v4
The frontend service would span both sets of replicas by selecting the common subset of their labels,so that the traffic will be redirected to both applications:
selector: app: guestbook tier: frontend
You can tweak the number of replicas of the stable and canary releases to determine the ratio of each release that will receive live production traffic(in the case 3:1).Once you're confident,you can update the stable track to the new application release and remove the canary one.
有些时候已经存在的pods和其他资源需要在创建新资源之前重新打标签。
# kubectl label pods -l app=nginx tier=fe pod "my-nginx-2035384211-t2trb" labeled pod "my-nginx-2035384211-xlgvr" labeled pod "my-nginx-2035384211-ykqit" labeled
# kubectl get pods -l app=nginx -L tier NAME READY STATUS RESTARTS AGE TIER my-nginx-2035384211-t2trb 1/1 Running 0 22h fe my-nginx-2035384211-xlgvr 1/1 Running 0 22h fe my-nginx-2035384211-ykqit 1/1 Running 0 22h fe
为pods添加注释
# kubectl annotate pods my-nginx-2035384211-t2trb description='my frontend running nginx' pod "my-nginx-2035384211-t2trb" annotated
# kubectl get pods my-nginx-2035384211-t2trb -o yaml apiVersion: v1 kind: Pod metadata: annotations: description: my frontend running nginx kubernetes.io/created-by: | {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"my-nginx-2035384211","uid":"86efd0b1-8c9f-11e6-a500-0050568f7dea","apiVersion":"extensions","resourceVersion":"473947"}} creationTimestamp: 2016-10-07T15:05:47Z generateName: my-nginx-2035384211- labels: app: nginx pod-template-hash: "2035384211" tier: fe name: my-nginx-2035384211-t2trb namespace: default resourceVersion: "528222" selfLink: /api/v1/namespaces/default/pods/my-nginx-2035384211-t2trb uid: 86f16943-8c9f-11e6-a500-0050568f7d
调整应用规模
当发现应用复制增加或者缩小时,很容易使用kubectl来对应用进行扩大规模或者缩小规模。例如,减小nginx副本数量从3到1
# kubectl scale deployment/my-nginx --replicas=1 deployment "my-nginx" scaled # kubectl get pods -l app=nginx NAME READY STATUS RESTARTS AGE my-nginx-2035384211-xlgvr 1/1 Running 0 22h
使系统根据需要自动选择nginx副本,范围从1到3
]# kubectl autoscale deployment/my-nginx --min=1 --max=3 deployment "my-nginx" autoscaled
有些时候有必要对创建的资源非强制性地更新
kubectl apply
建议通过源码控制方式来维护配置文件,这样它们可以同配置的资源代码一起进行版本维护.可以使用kubectl apply来推送配置变更到kubernetes集群。这个命令会比对现在的配置版本和之前的配置版本,然后应用变更,而不需要覆盖没有指定的属性。
# kubectl apply -f /opt/software/kubernetes/docs/user-guide/nginx-deployment.yaml deployment "nginx-deployment" configured
另外,可以使用kubectl edit更新资源
# kubectl edit deployment/my-nginx deployment "my-nginx" edited
等同于
$ kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml $ vi /tmp/nginx.yaml # do some edit, and then save the file $ kubectl apply -f /tmp/nginx.yaml deployment "my-nginx" configured $ rm /tmp/nginx.yaml
假设想要修复容器镜像的一个错误,可以使用kubectl patch
# Suppose you have a Deployment with a container named "nginx" and its p_w_picpath "nignx" (typo), # use container name "nginx" as a key to update the p_w_picpath from "nignx" (typo) to "nginx" $ kubectl get deployment my-nginx -o yaml apiVersion: extensions/v1beta1 kind: Deployment ... spec: template: spec: containers: - p_w_picpath: nignx name: nginx ...
$ kubectl patch deployment my-nginx -p'{"spec":{"template":{"spec":{"containers":[{"name":"nginx","p_w_picpath":"nginx"}]}}}}' "my-nginx" patched $ kubectl get pod my-nginx-1jgkf -o yaml
apiVersion: extensions/v1beta1 kind: Deployment ... spec: template: spec: containers: - p_w_picpath: nginx name: nginx ...
强制更新
在有些情况下,可能需要更新初始化后无法更新的资源字段,或者可能只想要立刻做一个递归变更,比如修复坏掉的pods。
# kubectl replace -f /opt/software/kubernetes/docs/user-guide/nginx-deployment.yaml --force deployment "nginx-deployment" deleted deployment "nginx-deployment" replaced
不中断服务的情况下更新应用
在某个时候,最终需要更新部署的应用,典型地指定一个新的镜像或者镜像tag。
假如现在运行的是nginx 1.7.9
# kubectl run my-nginx --p_w_picpath=nginx:1.7.9 --replicas=3 deployment "my-nginx" created
更新到nginx 1.9.1,只需要使用kubectl edit 修改 .spec.template.spec.containers[0].p_w_picpath 版本号从1.7.9改为1.9.1
# kubectl edit deployment/my-nginx
Replication Controller Operations
一个复制控制器确保任何同一时刻指定数量的pod副本正常运行。如果太多,它就会杀掉一些pod副本,如果太少,它就会启动多一些pod副本。
使用kubectl create 创建复制控制器
$ kubectl create -f FILE
{ "apiVersion": "v1", "kind": "ReplicationController", "metadata": { "name": "", "labels": "", "namespace": "" }, "spec": { "replicas": int, "selector": { "":"" }, "template": { "metadata": { "labels": { "":"" } }, "spec": { // See 'The spec schema' below } } }}
kind: 值总是ReplicationController
apiVersion:
列出一个kubernetes集群的复制控制器
$ kubectl get rc
查看指定复制控制器的信息
$ kubectl describe rc NAME
将复制控制器和它控制的pods一并删除
$ kubectl delete rc NAME
默认情况下,kubectl delete rc 删除复制控制器之前会重置复制控制器的大小为0(删除所有的pods)。如果想要删除一个复制控制器的时候不删除它的pods,可以
$ kubectl delete rc NAME --cascade=false
调整复制控制器的大小
减少或者增加一个复制控制器控制的pods数量,可以使用kubectl scale命令
$ kubectl scale rc NAME --replicas=COUNT \ [--current-replicas=COUNT] \ [--resource-version=VERSION]
rc 代表replicationcontroller
NAME 复制控制器的名称
--replicas=COUNT 期望副本的数量
可选参数:
--current-replicas=COUNT 当前副本数量。
--resource-version=VERSION 资源版本
Rolling Updates
为了不中断服务更新应用,kubectl支持rolling update,一次更新一个pod而不是同时更换整个服务。
kubectl rolling-update 只支持复制控制器Replication Controllers.然而,如果你使用Replication Controllers部署应用,可以考虑转换Replication Controllers到Deployments。
A deployment is a higher-level controller that automates rolling updates of applications declaratively,and therefore is recommened.
rolling update滚动更新就是对replication controller管理的pods进行配置变更应用。变更的内容可以作为一个新的replication controller配置文件。
rolling update工作步骤:
根据要更新的配置文件创建一个新的replication controller
在新旧controllers上增加或者减少pod副本数量直到达到正确的副本数量。
删除原始的replication controller
$ kubectl rolling-update NAME \ ([NEW_NAME] --p_w_picpath=IMAGE | -f FILE)
$ kubectl rolling-update NAME -f FILE
// Update pods of frontend-v1 using new replication controller data in frontend-v2.json. $ kubectl rolling-update frontend-v1 -f frontend-v2.json // Update pods of frontend-v1 using JSON data passed into stdin. $ cat frontend-v2.json | kubectl rolling-update frontend-v1 -f -
$ kubectl rolling-update NAME [NEW_NAME] --p_w_picpath=IMAGE:TAG
--p_w_picpath 标志只支持single-container pods
// Update the pods of frontend-v1 to frontend-v2 $ kubectl rolling-update frontend-v1 frontend-v2 --p_w_picpath=p_w_picpath:v2 // Update the pods of frontend, keeping the replication controller name $ kubectl rolling-update frontend --p_w_picpath=p_w_picpath:v2
参考案例:
假设正在运行nginx 1.7.9
apiVersion: v1kind: ReplicationControllermetadata: name: my-nginxspec: replicas: 5 template: metadata: labels: app: nginx spec: containers: - name: nginx p_w_picpath: nginx:1.7.9 ports: - containerPort: 80
为了升级到nginx 1.9.1,可以使用kubectl rolling-update --p_w_picpath 来指定新的镜像
$ kubectl rolling-update my-nginx --p_w_picpath=nginx:1.9.1 Created my-nginx-ccba8fbd8cc8160970f63f9a2696fc46
$ kubectl get pods -l app=nginx -L deployment NAME READY STATUS RESTARTS AGE DEPLOYMENT my-nginx-ccba8fbd8cc8160970f63f9a2696fc46-k156z 1/1 Running 0 1m ccba8fbd8cc8160970f63f9a2696fc46 my-nginx-ccba8fbd8cc8160970f63f9a2696fc46-v95yh 1/1 Running 0 35s ccba8fbd8cc8160970f63f9a2696fc46 my-nginx-divi2 1/1 Running 0 2h 2d1d7a8f682934a254002b56404b813e my-nginx-o0ef1 1/1 Running 0 2h 2d1d7a8f682934a254002b56404b813e my-nginx-q6all 1/1 Running 0 8m 2d1d7a8f682934a254002b56404b813e
rolling-update进度
Scaling up my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 from 0 to 3, scaling down my-nginx from 3 to 0 (keep 3 pods available, don't exceed 4 pods) Scaling my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 up to 1 Scaling my-nginx down to 2 Scaling my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 up to 2 Scaling my-nginx down to 1 Scaling my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 up to 3 Scaling my-nginx down to 0 Update succeeded. Deleting old controller: my-nginx Renaming my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 to my-nginx replicationcontroller "my-nginx" rolling updated
Rolling Update Demo
第0步 Prerequisties
$ git clone -b master $ cd kubernetes.github.io
第1步 Turn up the UX for the demo
$ kubectl proxy --www=docs/user-guide/update-demo/local/ & I0218 15:18:31.623279 67480 proxy.go:36] Starting to serve on localhost:8001
第2步 Run the replication controller
$ kubectl create -f docs/user-guide/update-demo/nautilus-rc.yaml
第3步 Try scaling the replication controller
$ kubectl scale rc update-demo-nautilus --replicas=4
第4步 Update the docker p_w_picpath
$ kubectl rolling-update update-demo-nautilus --update-period=10s -f docs/user-guide/update-demo/kitten-rc.yaml
第5步 Bring down the pods
$ kubectl delete rc update-demo-kitten
第6步 Cleanup
$ jobs[1]+ Running ./kubectl proxy --www=local/ & $ kill %1[1]+ Terminated: 15 ./kubectl proxy --www=local/
Secrets Walkthrough
$ kubectl create -f docs/user-guide/secrets/secret.yaml
Horizontal Pod Autoscaling
Horizontal Pod Autoscaling会根据观察到的CPU使用率自动地扩展replication controller,deployment或者replica set中的pods数量
Step1: Run&expose php-apache server
$ kubectl run php-apache --p_w_picpath=gcr.io/google_containers/hpa-example --requests=cpu=200m --expose --port=80 service "php-apache" created deployment "php-apache" created
Step2: Create Horizontal Pod Autoscaler
$ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10 deployment "php-apache" autoscaled
$ kubectl get hpa NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE php-apache Deployment/php-apache/scale 50% 0% 1 10 18s
Step3: Increase load
$ kubectl run -i --tty load-generator --p_w_picpath=busybox /bin/sh Hit enter for command prompt $ while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done
$ kubectl get hpa NAME REFERENCE TARGET CURRENT MINPODS MAXPODS AGE php-apache Deployment/php-apache/scale 50% 305% 1 10 3m
$ kubectl get deployment php-apache NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE php-apache 7 7 7 7 19m
Step4: Stop load
从 .yaml文件中创建一个autoscaler
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: php-apache namespace: default spec: scaleTargetRef: apiVersion: extensions/v1beta1 kind: Deployment name: php-apache minReplicas: 1 maxReplicas: 10 targetCPUUtilizationPercentage: 50
$ kubectl create -f docs/user-guide/horizontal-pod-autoscaling/hpa-php-apache.yaml horizontalpodautoscaler "php-apache" created
Best Practices for Configuration
当定义配置信息时,指定最新稳定的API版本
配置文件在应用到集群之前应当存放到版本管理工具上
使用YAML格式编写配置文件
组相关的对象写在单个配置文件中
不用指定非必要的默认值
为每个对象添加个描述信息
尽量不单独使用Pods,优先使用replication controllers。Naked pods运行失败后不会被重新调度
最好在创建相应的replication controllers之前创建一个service.那样调度器可以展开组成这个service的pods。也可以创建一个replication controller但不指定replicas(默认replicas=1).然后再向上扩展replication controller.这样的好处就是创建更多replicas之前确认好一个工作正常
不使用hostPort
避免使用hostNetwork
参考文档:
http://kubernetes.io/docs/whatisk8s/
https://aucouranton.com/2014/06/13/linux-containers-parallels-lxc-openvz-docker-and-more/
http://kubernetes.io/p_w_picpaths/docs/why_containers.svg
https://docs.docker.com/engine/installation/linux/centos/
http://kubernetes.io/docs/getting-started-guides/centos/centos_manual_config/
http://kubernetes.io/docs/getting-started-guides/scratch/