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。
一个项目要集成k8s,说白了就是写一些配置文件,这些配置文件可以给kubectl
的各种命令使用。
首先是kind:Deployment
,Deployment
配置文件的作用是定制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
镜像提供的服务是一样的。
然后就是 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 。
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 中的服务了。
# 查看部署的deployment和pod等,后面跟上命名空间的参数
kubectl get deployments --namespace 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}