DevOps:容器篇

1. docker

Docker 是一个应用容器引擎,说简单点就是将你的应用里三层外三层打包成一个镜像,然后用一条命令将镜像跑起来,本质上它就是一个进程而已,只不过使用了一些隔离技术(cgroups 、namespace、rootfs、setns)让其“隐藏”起来,从而感觉上它是一个容器,而且是一个独立的系统。docker和虚拟机有着本质的区别,虚拟机会占用更多的物理资源,虚拟机比较笨重,重建或释放都比较费时。例如有个1000平的大房子,如果隔成10个甚至20个小房间都没问题,而且可以随时拆掉再隔;但如果在里面盖房子的话,可能盖5间就不错了。


image.png

用以下命令揭示“容器”的真实身份

# 查看 a776ea6f142d2819 容器的进程号
[root@node1 ~]# docker inspect --format '{{ .State.Pid }}'  a776ea6f142d
2819
# 发现容器在宿主机中进程
[root@node1 ~]# ps -aux |grep 2819
root     22819  0.0  0.0 109096  6604 ?        Sl   Apr28   3:40 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/a2b9a823d8451eaa32c92330599e7167dc69b46930746b536ec018ca91e30914 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc -systemd-cgroup

2. kubernetes

Kubernetes是Google开源的一个容器编排引擎,随着docker的流行,当运行数百、数千个容器时,人们就不得不考虑一个问题,如何让容器更高效的运行、以及如何在分布式环境下运行容器等。这是k8s就横空出世了,它简化了大规模部署的容器管理问题,而在k8s流行之前,docker公司就有三剑客的另外两个产品:docker-compose、swarm。swarm是docker公司主推的容器编排工具,也是和k8s一决高下的产品,但最终用户用脚投票,k8s以完胜收场,这里不得不提的一个大牛就是Tower(高塔),作为k8s的布道师功不可没。

一、架构

image.png

(1) kubectl

集群的客户端命令行工具,请求apiserver的rest接口,查看和维护集群,kubectl需要一个配置文件: kubeconfig,此文件包含用户、集群上下文、命名空间、认证机制信息等,kubectl可以同时管理多个集群,在请求apiserver需要认证信息。kubectl可以同时管理多个集群。

(2) kube-apiserver

API Server提供了资源对象的唯一操作入口,其他所有组件都必须通过它提供的API来操作资源数据,只有API Server与存储通信,其他模块通过API Server访问集群状态。以RESTFul接口方式提供给外部客户和内部组件进行同一调用。

(3) kube-controller-manager

实现集群故障检测和恢复的自动化工作,负责执行各种控制器,主要有:

  • endpoint-controller:定期刷新service和pod(关联信息由endpoint对象维护)的关联关系,保证service到pod的映射总是最新的。

  • replication-controller:定期检查replicationController(新版叫ReplicaSet)中配置的pod数量和实际运行数量是否一致,如果不一致会自动启动或停止pod。

(4) kube-scheduler

Scheduler收集和分析当前Kubernetes集群中所有Work节点的资源(内存、CPU)负载情况,然后分发Pod到集群中可用的节点上,并实时监测集群中未分发和已分发的所有运行的Pod,将已分发的pod信息写回到API Server。为了避免频繁查询,Scheduler会缓存一份最新的信息在本地。

(5) etcd

和Zookeeper类似,负责存储各个组件的共享数据,保证集群高可用。

(6) kube-proxy

负责接收并转发请求。Kube-proxy的核心功能是将到达Service的访问请求转发到后台的某个具体的Pod。无论是通过ClusterIP+Port的方式还是NodeIP+NodePort的方式访问Service,最终都会被节点的Iptables规则(新版本是通过LVS转发)重定向到Kube-proxy监听服务代理端口,该代理端口实际上就是SocketServer在本地随机打开的一个端口,SocketServer是Kube-proxy为每一个服务都会创建的“服务代理对象”的一部分。当Kube-proxy监听到Service的访问请求后,它会找到最适合的Endpoints,然后将请求转发过去。具体的路由选择依据Round Robin算法及Service的Session会话保持这两个特性。

(7) kubelet

运行在每个work节点上,作为agent,负责分配该Node上的Pods任务、启动Pod、管理容器、周期性获取容器状态等,反馈给kube-apiserver。注意:kubelet 与 kube-apiserver 之间的通信是双向的, kubelet 既需要访问 kube-apiserver 获取分配到自己节点上的 pod 信息, kube-apiserver 也需要主动访问 kubelet 拉取日志, 状态, 监控数据等信息, 所以对两个组件来说, 认证是双向的, kube-apiserver 需要持有 kubelet 的客户端证书, 以完成 kubelet 对自己身份的校验; kubelet 也需要持有 kube-apiserver 的客户端证书, 完成 kube-apiserver 对自己身份的认证。
通过kubeadm安装时,Kubelet是唯一一个运行在宿主机上的服务,因为它负责启动容器,如果它也运行在容器中,那就成了它在容器中启动其他容器啦,这样会有很多不方便。

(8) kube-DNS

一个可选的DNS服务,用于为每个Service对象创建DNS记录,这样所有的Pod就可以通过DNS访问服务了。

(9) CRI

CRI是k8s对容器操作的统一抽象,在1.20版本之前,k8s直接调用docker的API,所以搞了一个 dockershim的适配器来完成,之前比较热的话题k8s要废弃docker,其实是废弃这个东西。目前k8s最新版对容器操作直接对接OCI(容器统一的开发标准)来完成,这样的好处不言而喻,不管什么容器厂家,只要实现了OCI标准,就能和k8s无缝对接,详细请看我的文章《docker的陨落》。

二、安装

使用kubeadm安装k8s非常简单,但经常失败,大致失败的原因有几点:

  • 镜像下载不下来,使用阿里云镜像,但版本比较老
  • 虚拟机,云主机等多网卡环境,需指定advertiseAddress,calico插件需要指定通信的网卡
  • pod网段和service网段和系统网段冲突
  • 浮动IP问题
  • OpenStack环境下容器跨节点无法通行问题,可尝试关闭port-security来解决
  1. 编写kubeadm配置文件: kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
# kubeadm 使用 eth0 的默认网络接口(通常是内网IP,在virtualbox一般是10.0.2.15)做为 Master节点的advertise address
# 如果是通过虚拟机安装k8s,那么必须设置advertiseAddress地址,否则导致其他节点无法正常和master通信
localAPIEndpoint:
  # 不能绑定浮动IP
  advertiseAddress: 10.0.2.24
  bindPort: 6443
  
---
# 开启Kube-proxy代理规则为ipvs,默认是Iptables
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"

---
apiVersion: "kubeadm.k8s.io/v1beta2"
kind: ClusterConfiguration
kubernetesVersion: v1.17.4
controlPlaneEndpoint: "apiserver:6443"
apiServer:
  extraArgs:
    service-node-port-range: 1000-40000
  certSANs:
  - 10.0.2.24
  - 127.0.0.1
networking:
  # podSubnet相当于--pod-network-cidr 参数
  podSubnet: 192.244.0.0/16
  # serviceSubnet相当于--service-network-cidr 参数
  serviceSubnet: 10.96.0.0/16
  1. 执行kubeadm初始化操作
#  加上此参数:--upload-certs ,其他节点加入时可以自动获取证书
$ kubeadm init --config=kubeadm-config.yaml --upload-certs
  1. 安装客户端,执行节点加入操作等
  2. 安装网络插件,推荐安装 calico 插件。

3. 应用部署

k8s内置了多种资源类型,如pod是k8s中最小的单元, ReplicaSet管理pod的多个副本,Deployment 是无状态应用。

下面是部署一个nginx到k8s集群,并设置有pod有3个副本

apiVersion: apps/v1
kind: Deployment

metadata:
  name: nginx-deployment
  labels:
    app: nginx

spec:
  replicas: 3
apiVersion: apps/v1
kind: Deployment

metadata:
  name: nginx-deployment
  labels:
    app: nginx

spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.cn-hangzhou.aliyuncs.com/moobox/nginx
        ports:
        - containerPort: 80---
#service
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:

  - port: 80
    protocol: TCP
    targetPort: 80
      selector:
    app: nginx
      type: ClusterIP
$ kubectl apply -f nginx.yaml
$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-6c84b7494d-gj5qk   1/1     Running   0          4m11s
nginx-deployment-6c84b7494d-j8fhz   1/1     Running   0          4m11s
nginx-deployment-6c84b7494d-xbvdf   1/1     Running   0          4m11s

4. 高级

一、监控

使用prometheus + Grafana监控k8s集群,支持operator的话,可下载kube-prometheus v0.5.0 版(最新版有一个镜像拉取不了)进行安装。安装完如果没有监控数据,可能是:

问题1: 时间不同步,时区不对,设置为本地时区和当前时间,查看
prometheus主页发现有警告,可通过timedatectl和date 命令修改

问题2:Grafana 的prometheus数据源,默认配置的是k8s内部域名地址,所以外部无法访问,数据源需要修改为外部的地址: http://192.168.x.x:39090/

二、蓝绿部署

k8s默认就支持滚动升级,蓝绿部署也是支持的,加入有个服务之前的版本是V1,新部署了一个版本是V2,那我们就可以通过两个service来实现一个简单的蓝绿部署

#service
apiVersion: v1
kind: Service
metadata:
  name: web-bluegreen-v1
  namespace: dev
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  # 通过选择不同版本的webapp,来切换流量  
  selector:
    app: webapp
    version: v1.0 #version: v2.0
  type: ClusterIP
#service
apiVersion: v1
kind: Service
metadata:
  name: web-bluegreen-v2
  namespace: dev
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  # 通过选择不同版本的webapp,来切换流量  
  selector:
    app: webapp
    version:  v2.0
  type: ClusterIP

k8s默认是不支持灰度发布的,想要实现灰度发布,可使用其他组件,如istio

三、自动扩容

HPA(Horizontal Pod Autoscaler)是k8s的一个资源对象,利用prometheus获取该资源对象的监控指标,可实现Pod自动伸缩。但有几点必须要注意:

  • pod一定要设置资源限制request、limit等,才能开启HPA
  • HPA控制器的时间窗口默认是15秒,即每隔15s拉取一次监控指标,可通过–horizontal-pod-autoscaler-sync-period参数设定
    kubernetes集群需要配置好metrics server
  • 目前是v1版本,从k8s v1.18 支持 v2beta2版本,可支持基于内存的伸缩指标,可自定义伸缩指标

基于内存/CPU的自动伸缩
下面我们对一个xxx应用进行自动伸缩,当CPU使用超过60%时,会自动增加pod,但不会超过6个

$ kubectl autoscale deployment xxx --cpu-percent=60 --min=2 --max=6

QPS的自动伸缩
下面创建一个HPA来实现 一个QPS的 自动伸缩:

apiVersion: autoscaling/v2beta2 
kind: HorizontalPodAutoscaler
metadata: 
  name: blog-web
spec: 
  scaleTargetRef: 
    apiVersion: apps/v1 
    kind: Deployment 
    name: blog-web
  minReplicas: 2
  maxReplicas: 8 
  metrics:
  - type: Pods
    pods:
      metric:
        name: http_requests_received
      target:
        type: AverageValue
        averageValue: 10

你可能感兴趣的:(DevOps:容器篇)