一 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.crtpki/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   frontend   
frontend-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/