K8s如何从私有Harbor中拉取镜像并完成部署

本章主要将如何将已经提交到Harbor仓库的镜像在k8s体系内完成部署工作。

简单扫盲

粗略介绍下k8s的内容体系,便于理解后面配置文件。

k8s体系简介

k8s整体可以分几个部分:namespace,configMap,deployment,pod,service,ingress。

namespace

命名空间,其实和java中namespace类似,主要是为了对k8s的对象进行区域划分以及资源隔离。

你可以认为每个namespace下的对象是不能够共享的。并且你可以针对namespace进行配置,设置这个namespace下可以使用的服务器资源的配额。例如cpu核心,存储,网络等等。

这里不再详述。

namespace简写ns

configMap

k8s的配置对象,可以绑定到k8s对象上面,让对象能够读取configMap中的配置信息,主要是key:value信息。当然是否要使用,需要自行判断。同时需要程序端配合。不然你运营配置了,程序没加载,依然没用。

deployment&pod

这俩需要一块说明一下。

K8s中的pod,你可以理解为docker中的容器。k8s中创建一个pod,就等于docker run创建了一个容器。也就是说pod是镜像的实例,是实际运行jar包或者nginx的对象。

pod实际上是可以单独创建的。

扫描二维码关注公众号,回复: 14651712 查看本文章

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

service

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

ingress

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部署

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环境和网络没问题!!!

猜你喜欢

转载自blog.csdn.net/lanwilliam/article/details/125906633