notes

k8s基本概念

k8s全称是Kubernetes,是基于容器技术(我们这里用docker)的分布式架构(容器集群管理系统)。

典型的 Kubernetes 集群包含一个 master 和很多 node。我们公司的 Master 是控制集群的中心,node 是提供 CPU、内存和存储资源的节点。Master 上运行着多个服务,包括面向用户的 API 服务、负责维护集群状态的 Controller Manager、负责调度任务的 Scheduler 等。每个 node 上运行着维护 node 状态并和 master 通信的 kubelet,以及实现集群网络服务的 kube-proxy。

学习k8s前,要先搞清楚其中的一些概念:

node:node 可以是虚拟机也可以是物理机,node中运行了很多服务,最主要的就是docker环境,可以运行docker。

滚动更新:在更新服务的过程中不会影响用户的访问,一般是创建新的pod,创建完成后再删除旧的pod。

kind:xxx 配置文件

一个项目要集成k8s,说白了就是写一些配置文件,这些配置文件可以给kubectl的各种命令使用。

Deployment

首先是kind:DeploymentDeployment配置文件的作用是定制Pod,指定使用哪个镜像来运行Pod中的容器,

一个deployment配置文件大概是这样子的:

# deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: k8s-test
  name: k8s-test
  namespace: gitlab

spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: k8s-test
  strategy:
    # type有recreate和rollingUpdate。
    # recreate--删除所有已存在的pod,重新创建新的; 
    # rollingUpdate--滚动升级,逐步替换的策略,同时滚动升级时,支持更多的附加参数,例如设置最大不可用pod数量,最小升级间隔时间等等。
    type: RollingUpdate
    rollingUpdate:
      # 最大激增数, 指更新过程中, 最多可以比replicas预先设定值多出的pod数量, 
      # 可以为固定值或百分比(默认25%), 更新过程中最多会有replicas + maxSurge个pod
      maxSurge: 25%
      # 最大无效数, 指更新过程中, 最多有几个pod处于无法服务状态,
      # 当maxSurge不为0时, 此栏位也不可为0, 整个更新过程中, 会有maxUnavailable个pod处于Terminating状态
      maxUnavailable: 25%
  template:
    metadata:
      labels:
        k8s-app: k8s-test
      name: k8s-test
    spec:
      containers:
      - image: gitlab.your.com/group/k8s-test:__CI_COMMIT_SHA__
        # 默认拉取镜像的策略是IfNotPresent,只要拉取过一次就不拉取了,如果像每次更新latest就是
        imagePullPolicy: Always
        name: k8s-test
        ports:
        - containerPort: 8081
          name: http
          # hostPort直接把pod的服务映射到主机的8991端口,在宿主机使用curl http://{pod_ip}:8991就可以访问到
          # 但是pod是不稳定的,每次挂了重启ip都会变,不推荐这种方式
          # hostPort: 8991
      # 如果您使用 docker 公共仓库,则无需填写,imagePullSecrets
      imagePullSecrets:
      - name: k8s-test-secret
      restartPolicy: Always

以上的配置文件我们可以直接用 kubectl create -f deployment.yaml ,就可以在 node 中创建一个 pod。如在以上例子中我们指定了 gitlab.your.com/group/k8s-test 作为镜像运行在pod中,那这个pod提供的服务和 gitlab.your.com/group/k8s-test 镜像提供的服务是一样的。

service

然后就是 kind:service 配置文件,deployment创建的pod理论上能使用集群内的ip:端口号直接访问,但是 pod 都是不稳定的,可能随时都会退出,然后重新起一个新的pod,但是新的pod的ip此时已经改变了,此时就需要service。

service是pod的路由代理抽象,用于解决pod之间的服务发现问题,即上下游pod之间使用的问题。传统部署方式中,实例所在的主机ip(或者dns名字)一般是不会改变的,但是pod的运行状态可动态变化(比如容器重启、切换机器了、缩容过程中被终止了等),所以访问端不能以写死IP的方式去访问该pod提供的服务。service的引入旨在保证pod的动态变化对访问端透明,访问端只需要知道service的地址,由service来提供代理。

servic的ip只能在node节点上才能访问,因为虚拟ip只在每一个node节点的iptables中映射。

一个service的配置文件例子:

# service.yaml

apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: k8s-test
  name: k8s-test-svc
  namespace: gitlab
spec:
  ports:
    # port和nodePort都是service的端口,前者暴露给k8s集群内部服务访问,后者暴露给k8s集群外部流量访问
  - port: 8081
    # 容器端口
    targetPort: 8081
    protocol: TCP
  selector:
    k8s-app: k8s-test
  # NodePort表示把service的端口映射到宿主机的端口
  type: NodePort

service 配置文件我们可以用 kubectl create -f service.yaml ,就可以创建一个 service , metadata -> label 字段说明这个 service 作用与哪些 pod 。

ingress

service 的服务也是给集群内部访问的,外部访问不了,所以要想外部访问的话,就需要用到 ingress 类型的配置文件。

kind:Ingress 类型默认没有在k8s里面,需要安装额外的扩展,我们这里是 ingress-nginx ,一个 ingress 配置文件如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: k8s-test-ingress
  namespace: gitlab
  annotations:
    # 表示将 /path 路径重定向到后端服务能够识别的根路径 /上面
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: your.host.com
    http:
      paths:
      - path: /
        backend:
          serviceName: k8s-test-svc
          servicePort: 8081

同样,可以使用命令 kubectl apply -f ingress.yaml 创建一个 ingress ,之后就能使用 your.host.com 访问 pod 中的服务了。

kubectl的常用命令

# 查看部署的deployment和pod等,后面跟上命名空间的参数
kubectl get deployments --namespace gitlab

如何拉取gitlab上的镜像

使用gitlab的账号密码在k8s服务器上登录一次

docker login <gitlab host:port> -u <gitlab username> -p <gitlab password>

登录后,/root/.docker/config.json这个目录会多一个auth信息,利用这个文件创建一个secret,用于拉取gitlab上的镜像

kubectl create secret generic <secret_name> --namespace=gitlab \
    --from-file=.dockerconfigjson=/root/.docker/config.json \
    --type=kubernetes.io/dockerconfigjson

在配置文件中使用变量

k8s的配置文件不支持变量,但是可以通过 linux 的 sed 命令动态替换配置文件中固定的字符串。

比如在上面的 deployment.yaml 中,我们指定的image的tag为 __CI_COMMIT_SHA__ ,实际上这里并不是环境变量什么的,而是随意些的一串字符串,我们需要在部署前把这串替换掉:

sed -i 's/__CI_ENVIRONMENT_SLUG__/${CI_ENVIRONMENT_SLUG}/' deployment.yaml

上面的命令意思是把配置文件中的 __CI_ENVIRONMENT_SLUG__ 字符串替换为 CI_ENVIRONMENT_SLUG(是一个环境变量) 。

快捷指令

每次切换命名空间太麻烦?

kubectl config set-context --current --namespace={namespace}

实战

部署一个真实的项目