本章主要将如何将已经提交到Harbor仓库的镜像在k8s体系内完成部署工作。
粗略介绍下k8s的内容体系,便于理解后面配置文件。
k8s整体可以分几个部分:namespace,configMap,deployment,pod,service,ingress。
命名空间,其实和java中namespace类似,主要是为了对k8s的对象进行区域划分以及资源隔离。
你可以认为每个namespace下的对象是不能够共享的。并且你可以针对namespace进行配置,设置这个namespace下可以使用的服务器资源的配额。例如cpu核心,存储,网络等等。
这里不再详述。
namespace简写ns
k8s的配置对象,可以绑定到k8s对象上面,让对象能够读取configMap中的配置信息,主要是key:value信息。当然是否要使用,需要自行判断。同时需要程序端配合。不然你运营配置了,程序没加载,依然没用。
这俩需要一块说明一下。
K8s中的pod,你可以理解为docker中的容器。k8s中创建一个pod,就等于docker run创建了一个容器。也就是说pod是镜像的实例,是实际运行jar包或者nginx的对象。
pod实际上是可以单独创建的。
kubectl create pod命令就可以创建一个pod容器。当然用kubectl apply一个yaml文件效果一样。
但是单独创建的pod有一些问题。
1. pod作为容器,是会动态分配ip的,动态分配的ip不可控。
2. pod被删除后,或者pod由于程序问题死掉了,是不会自动恢复的。也就是说,你直接创建的pod,如果执行了kubectl delete pod,那么pod就真的被删除掉了。不会享受到k8s的高可用。
这么玩费劲搞k8s有啥用?所以我们一般不会直接创建pod,而是将创建pod和pod管理这个事情托管给deployment。
deployment可以理解为一组管理策略。我们创建一个deployment,然后在里面指定我要启用几个pod,pod用什么镜像,需要配置什么env环境变量等等信息。
然后通过kubectl create deployment或者kubectl apply -f deployment.yaml创建deployment对象。那么k8s会根据deployment对象的配置,自行创建需要的pod。并且pod和deployement存在关联关系。
例如我deploy中定义要创建2个pod,那么系统中就会自动创建两个pod。这时你如果删除一个,那么系统会自动再重新创建一个pod,补足2个pod配置要求。同样的,pod死掉,系统也会自动补足2个,确保k8s平台有2个活着的pod。这是k8s高可用的一个前提。
deployment简写deploy
deploy虽然可以解决pod管理问题,但是依然无法解决pod动态ip的问题(这是由于框架需要决定的,毕竟pod随时可以扩展,并且随时会被替换,不适合制定固定ip)。于是我系统如何被请求到就出现一个问题。
k8s设计了service解决该问题。
service一旦被创建,那么ip变会被固定下来,并且service不是一容器形式存在,所以也不牵扯死掉重新创建等问题。所以k8s中,通过service将pod中的服务提供出来。
service一般是绑定到deploy上面,通过配置targetPort将deploy下pod的服务端口开放出来。并且service还具备负载均衡能力。如果deploy下配置了多个pod,那么service会根据负载均衡策略对pod进行轮训转发。这样就解决了pod动态ip,并且deploy下的pod可能会随时被替换的问题。
serivce简写svc
k8s的一个路由组件。
k8s提供的网络访问方式有3中,ClusterIP,NodePort,LoadBalancer。
ClusterIP方式,只能够在k8s集群内部服务器间通讯。
NodePort方式,可以将node上的pod或者service的业务端口映射到主节点上,从而可以通过主节点ip:映射端口方式,对集群外终端提供请求服务。
LoadBanlancer需要配合前端负载均衡服务或者设备使用,这里不提。
ClusterIP,显然无法满足外部请求需要;NodePort,小规模K8s的话可以使用,他最多可以使用1w左右节点,默认从3w以后开始分配。
为了满足大规模k8s集群应用,ingress诞生了。
ingress有几种,一般多用nginx实现版本。
他会在k8s集群中的每个worknode上创建一个示例pod,对改节点上的service和pod进行访问代理。
同时他可以定义一个全局的ingress服务,对每个node上的ingresscontroller进行管理。
同时,ingress可以提供域名和路由的配置,这样就是先了外部请求进入ingress,ingress根据配置进行匹配,匹配到响应服务后,转发到对应节点的对应服务上,从而完成服务对外提供。就解决了端口问题。
例如:
www.abc.cn->svc1
www.def.cn->svc2
k8s部署说白了就是从harbor拉取镜像,创建容器,然后配置网络,实现外部对容器的请求。
整体用到的内容,就是上面扫盲的内容。
具体实现的办法,是通过yaml,完成上面内容的配置,然后通过kubectl apply -f xxx.yaml完成相关对象的创建。
模板代码
- apiVersion: v1
- kind: Namespace
- metadata:
- name: mysql
- #对应部署的命名空间
- ---
- apiVersion: v1
- kind: ConfigMap
- #类型为configmap
- metadata:
- name: uaa
- namespace: mysql
- #对应部署的命名空间
- data:
- application.yml: ''
-
- ---
- apiVersion: apps/v1
- kind: Deployment
- #类型为deployment,deployment主要管理无状态应用
- metadata:
- labels:
- app: uaa
- name: uaa #应用名称
- namespace: mysql #所属命名空间
- spec:
- replicas: 1 # 配置创建pod实例数量
- selector: # k8s中对象的关联关系就是通过对对象打label和selector实现的绑定 所有符合selector的对象都是改对象的关联对象
- matchLabels: &id001 # yaml中锚点,类似变量
- app: uaa
- app-pod: uaa
- template:
- metadata:
- annotations:
- serialNumber: '20220523094344'
- labels: *id001 # 引用上面定义的锚点 变量的值
- namespace: mysql
- spec:
- containers:
- - args: []
- env:
- - name: RUNTIME
- value: docker
- - name: RUNTIME_ENV
- value: prd
- - name: RUNTIME_MYSQL_PASSWORD #数据库密码
- value: '123456'
- - name: spring.redis.host #redis ip
- value: 192.168.216.219
- image: shandong.harbor.cn:55443/test/uaa:1.3.39 #镜像版本
- imagePullPolicy: Always #镜像拉取策略
- name: test-uaa
- ports:
- - containerPort: 8080
- readinessProbe:
- initialDelaySeconds: 5
- periodSeconds: 3
- tcpSocket:
- port: 8080
- resources:
- limits: #资源限制
- cpu: '8'
- memory: 2G
- requests:
- cpu: 100m
- memory: 500m
- volumeMounts:
- - mountPath: /var/log/andevopslog
- name: logpath
- imagePullSecrets:
- - name: images-registry #定义镜像拉取的密钥 需要按照harbor账号密码进行配置
- initContainers: #初始化容器,初始化如果要执行sql,打镜像的时候写在初始化容器里,先于主容器执行
- - command:
- - sh
- - -c
- - mysql -h$RUNTIME_MYSQL_HOST -P$RUNTIME_MYSQL_PORT -u$RUNTIME_MYSQL_USER
- -p$RUNTIME_MYSQL_PASSWORD < /opt/app/upgrade_sql/update.sql
- env: #环境变量同上
- - name: RUNTIME_MYSQL_PASSWORD
- value: '123456'
- - name: SQL_EXECUTE_MODE
- value: upgrade
- - name: server.port
- value: '8080'
- name: init-uaa-sql-execute-job
- restartPolicy: Always
- volumes:
- - emptyDir: {}
- name: logpath
-
- ---
- apiVersion: v1
- kind: Service #定义服务名,k8s内部访问的端口
- metadata:
- labels: &id001
- app-pod: uaa
- name: uaa
- namespace: mysql
- spec:
- ports:
- - name: http-80
- port: 80 #k8s集群内部服务之间访问service的入口
- targetPort: 8080 #容器的端口
- selector: *id001
-
- ---
- apiVersion: extensions/v1beta1
- kind: Ingress #定义对外暴露使用的方式为ingress
- metadata:
- annotations:
- nginx.ingress.kubernetes.io/rewrite-target: /$2
- labels:
- app: uaa
- name: uaa
- namespace: mysql
- spec:
- rules:
- - host: demo.test.com.cn #对外暴露使用的域名
- http:
- paths:
- - backend:
- serviceName: uaa #对外暴露指向内部的服务名service
- servicePort: 80
- path: /test/uaa(/|$)(.*) #路由地址
-
- ---
上面模板包含了一个后台应用上线需要配置的所有相关对象。
这里要说明的是,env下配置的环境变量,需要和研发配合才能生效,否则就算容器配置了该变量,也不一定起作用,后面会单独讲解。
使用的时候,根据需要,修改namespace,各个对象的name,镜像信息,env信息,端口,ingress的域名和路由即可。
模板代码
- apiVersion: v1
- kind: Namespace
- metadata:
- name: mysql #定义部署的命名空间
-
- ---
- apiVersion: v1
- kind: ConfigMap #定义类型为configmap,configmap主要是一些配置,下发是nginx的配置
- metadata:
- name: coreweb
- namespace: mysql
- data:
- nginx.conf: |
- #user nobody;
- worker_processes 1;
-
-
- #error_log logs/error.log;
- #error_log logs/error.log notice;
- #error_log logs/error.log info;
-
- #pid logs/nginx.pid;
-
- events {
- worker_connections 1024;
- }
-
-
- http {
- include mime.types;
- default_type application/octet-stream;
-
- #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
- # '$status $body_bytes_sent "$http_referer" '
- # '"$http_user_agent" "$http_x_forwarded_for"';
-
- #access_log logs/access.log main;
-
- sendfile on;
- tcp_nopush on;
- client_max_body_size 500m;
-
- #keepalive_timeout 0;
- keepalive_timeout 200;
-
- gzip on;
- gzip_vary on;
- gzip_min_length 1k;
- gzip_comp_level 4;
- gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript;
- gzip_disable "MSIE [1-6]\.";
- add_header X-Frame-Options DENY;
-
- server {
- listen 8080; #端口
- server_name localhost;
-
- location ^~ / {
- #root html;
- alias /usr/share/nginx/html/; #这里路径要和dockerfile中copy的前端文件路径一致
- index index.html index.htm;
- try_files $uri $uri/ /index.html;
- client_max_body_size 500m;
- }
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root html;
- }
- }
- }
-
- ---
- apiVersion: apps/v1
- kind: Deployment #类型为deployment,deployment主要管理无状态应用
- metadata:
- labels:
- app: coreweb
- name: coreweb
- namespace: mysql
- spec:
- replicas: 1
- selector:
- matchLabels: &id001
- app: coreweb
- app-pod: coreweb
- template:
- metadata:
- annotations:
- serialNumber: '20220523124824'
- labels: *id001
- namespace: mysql
- spec:
- containers: #定义容器内的环境变量,前端不会请求这些变量,可有可无
- - args: []
- env:
- - name: RUNTIME
- value: docker
- - name: RUNTIME_ENV
- value: prd
- image: shandong.harbor.cn:55443/test/coreweb:1.3.229 #镜像版本
- imagePullPolicy: Always #镜像拉取策略
- name: onepark-coreweb
- ports:
- - containerPort: 8080
- readinessProbe:
- initialDelaySeconds: 5
- periodSeconds: 3
- tcpSocket:
- port: 8080
- resources:
- limits:
- cpu: '8'
- memory: 2G
- requests:
- cpu: 100m
- memory: 500m
- volumeMounts:
- - mountPath: /var/log/andevopslog #容器日志路径
- name: logpath
- - mountPath: /etc/nginx/nginx.conf #将configmap挂载进去
- name: config
- subPath: nginx.conf
- imagePullSecrets:
- - name: image-secret #定义镜像拉取的密钥
- restartPolicy: Always
- volumes:
- - emptyDir: {} #emptyDir类型的volume在pod分配到node上时被创建,kubernetes会在node上自动分配 一个目录,因此无需指定宿主机node上对应的目录文件。这个目录的初始内容为空,当Pod从node上移除时,emptyDir中的数据会被永久删除。
- name: logpath
- - configMap:
- name: coreweb
- name: config
-
- ---
- apiVersion: v1
- kind: Service #定义服务名,k8s内部访问的端口
- metadata:
- labels: &id001
- app-pod: coreweb
- name: coreweb
- namespace: mysql
- spec:
- ports:
- - name: http-80
- port: 80 #k8s集群内部服务之间访问service的入口
- targetPort: 8080 #容器的端口
- selector: *id001
-
- ---
- apiVersion: extensions/v1beta1
- kind: Ingress #定义对外暴露使用的方式为ingress
- metadata:
- annotations:
- nginx.ingress.kubernetes.io/rewrite-target: /$2
- labels:
- app: coreweb
- name: coreweb
- namespace: mysql
- spec:
- rules:
- - host: web.demo.cn #定义访问的域名
- http:
- paths:
- - backend:
- serviceName: test #对外暴露指向内部的服务名service
- servicePort: 80
- path: /()(.*)
-
- ---
前端就相对简单了,主要是nginx的配置要对起来。
下面给一个示例图片

PS:
首先你要先确保你的k8s环境和网络没问题!!!