Kubernetes

制作镜像

制作镜像分为三步:

  • 第一步基础镜像,是基于哪个操作系统,比如CentOS 7或者其他的
  • 第二步中间件镜像,比如服务镜像,跑的像Nginx服务,Tomcat服务
  • 第三步项目镜像,它是服务镜像之上的,将项目打包进去,那么这个项目就能在这个服务镜像里面运行了

Kubernetes部署应用的操作流程 - 图1
一般运维人员都是提前将镜像做好,而开发人员就能直接拿这个镜像去用,这个镜像一定要符合现在环境部署的环境。

控制器管理Pod

也就是Kubernetes去部署这个镜像了,一般都会去拿控制器去部署,用的最多的就是Deployment。

  • Deployment:无状态部署
  • StatefulSet:有状态部署
  • DaemonSet:守护进程部署
  • Job & CronJob:批处理

无状态和有状态的有什么区别?
有状态的是有身份的,比如网络ID、存储,这两个是提前规划好的,有序启动/停止。

Pod数据持久化

Pod数据持久化主要是应对一个应用程序说的,比如开发一个项目,这个项目有没有落地到本地文件,如果有落的话,就保证他持久的有了,那就必须要用到Pod数据的持久化了。
Kubernetes部署应用的操作流程 - 图2
容器部署过程中一般有以下三种数据:

  • 启动时需要的初始数据,可以是配置文件
  • 启动过程中产生的临时数据,该临时数据需要多个容器间共享
  • 启动过程中产生的持久化数据

    暴露应用

    在Kubernetes中,部署一个Deployment是无法对外进行访问的,就是别的应用程序要想访问部署的Deployment,找不到该怎么去访问,为什么这么讲,因为Deployment一般都是多副本部署的,有可能会分布在不同的节点之上,而且重建Pod IP也会变,重新发布一下也会改变,所以没有办法去固定去访问哪个Pod,即使固定了,其他的Pod也访问不了,要想做到多个Pod都去提供服务,前面就必须要加一个负载均衡,提供一个访问入口,只有访问这个统一入口,才能转发到后端多个Pod上,只要访问这个Cluster IP就能转发到后端的Pod上。
    Kubernetes部署应用的操作流程 - 图3

    Service

  • Service定义了Pod的逻辑集合和访问这个集合的策略

  • Service的引入为解决Pod的动态变化,提供了服务发现和负载均衡
  • 使用CoreDNS解析Service名称

    对外发布应用

    Kubernetes部署应用的操作流程 - 图4
    暴露出去之后,也就是需要让用户去访问,比如搭建一个电商网站,让用户去访问,Ingress相对于Service,是一个互补的状态,Service主要提供了集群内部的访问,也可以暴露一个TCP/UDP的端口,而Ingress主要是一个7层的转发,也就是提供一个统一的入口,只要访问Ingress Controller,就能转发部署所有的项目,也就是所有的项目都使用域名去访问。

    传统部署与Kubernetes部署的区别

    Kubernetes部署应用的操作流程 - 图5
    传统部署首先开发者将代码部署到代码仓库中,主流是使用Git或者GitLab,提交完代码通过CI/CD平台需要对代码进行拉取、编译、构建,产生一个War包,交给Ansible,然后发送到云主机上/物理机,之后通过负载均衡将项目暴露出去,最后会有数据库,监控系统,日志系统来提供相关的服务。
    Kubernetes部署应用的操作流程 - 图6
    Kubernetes部署首先也是开发将代码放在代码仓库,然后通过Jenkins去完成拉取代码,编译,上传到镜像仓库,这里是将代码打包成一个镜像,而不是刻意执行的war或者jar包,这个镜像包含了项目的运行环境和项目代码,这个镜像可以放在任何Docker上去run起来,都可以去访问,首先得保证能够在Docker上去部署起来,再部署到Kubernetes上,打出来的镜像去放在镜像仓库中,来集中管理这些镜像。
    因为每天会产生几十或者上百个镜像,所以必须通过镜像仓库去管理,这里可能会去写一个脚本去连接Kubernetes Master,而Kubernetes会根据自己的部署去调度这些Pod,然后通过Ingress去发布应用,让用户去访问。每个Ingress会关联一组Pod,而Service会创建这组Pod的负载均衡,通过Service去区分这些节点上的Pod,数据库放在集群之外,监控系统、日志系统也可以放在Kubernetes集群去部署,也可以放在集群之外。放在Kubernetes集群内的,也不是特别敏感,主要用来运维和开发调试用,不会影响到业务,所以优先去Kubernetes中部署。
    现在去部署一个Java项目到Kubernetes中。

    1、安装OpenJDK

    1. [root@k8s-master ~]# yum -y install java-1.8.0-openjdk.x86_64 maven
    2. [root@k8s-master ~]# java -version
    3. openjdk version "1.8.0_222"
    4. OpenJDK Runtime Environment (build 1.8.0_222-b10)
    5. OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
    然后将代码拉到本地一般Dockerfile中,跟代码都放在同一目录下。
    1. [root@k8s-master tomcat-java-demo-master]# ls
    2. db Dockerfile LICENSE pom.xml README.md src
    3. [root@k8s-master tomcat-java-demo-master]# vim Dockerfile
    4. FROM lizhenliang/tomcat
    5. LABEL maintainer zhaochengcheng
    6. RUN rm -rf /usr/local/tomcat/webapps/*
    7. ADD target/*.war /usr/local/tomcat/webapps/ROOT.war

    2、使用Maven进行编译

    这里需要配置Maven的国内源,这样比较快一点。
    1. [root@k8s-master CI]# vim /etc/maven/settings.xml
    2. <mirror>
    3. <id>central</id>
    4. <mirrorOf>central</mirrorOf>
    5. <name>aliyun maven</name>
    6. <url>https://maven.aliyun.com/repository/public</url>
    7. </mirror>
    8. </mirrors>
    9. [root@k8s-master tomcat-java-demo-master]# mvn clean package -D maven test.skip=true
    10. [root@k8s-master tomcat-java-demo-master]# ls
    11. db Dockerfile LICENSE pom.xml README.md src target
    12. [root@k8s-master tomcat-java-demo-master]# cd target/
    13. [root@k8s-master target]# ls
    14. classes generated-sources ly-simple-tomcat-0.0.1-SNAPSHOT ly-simple-tomcat-0.0.1-SNAPSHOT.war maven-archiver maven-status
    15. [root@k8s-master tomcat-java-demo-master]# cd target/
    就使用这个编译好的war包,打成镜像,上传到Harbor仓库里。 ```bash [root@k8s-master target]# ls classes ly-simple-tomcat-0.0.1-SNAPSHOT maven-archiver generated-sources ly-simple-tomcat-0.0.1-SNAPSHOT.war maven-status

[root@k8s-master tomcat-java-demo-master]# docker build -t 192.168.30.24/library/java-demo:latest .

  1. <a name="fBYD8"></a>
  2. #### 3、上传到镜像仓库
  3. ```bash
  4. [root@k8s-master tomcat-java-demo-master]# docker login 192.168.30.24
  5. Username: admin
  6. Password:
  7. Error response from daemon: Get https://192.168.30.24/v2/: dial tcp 192.168.30.24:443: connect: connection refused

这里报错,其实需要在每台Docker下都写入对Harbor仓库的信任才可以,后面上传镜像也会用。

  1. [root@k8s-master java-demo]# vim /etc/docker/daemon.json
  2. {
  3. "registry-mirrors": ["http://f1361db2.m.daocloud.io"],
  4. "insecure-registries": ["192.168.30.24"]
  5. }

再等录一下push就可以了。

  1. [root@k8s-master tomcat-java-demo-master]# docker push 192.168.30.24/library/java-demo:latest

Kubernetes部署应用的操作流程 - 图7

4、控制器管理Pod

编写Deployment,一般项目都写到自定义的命名空间下,名称写项目名称,方便记忆:

  1. name: tomcat-java-demo
  2. namespace: test

另外就是下一个项目名称,这里分为多个,一般由很多的组件组成,所以下面可以写个APP的名称,比如组件1、2、3,起码标签有这两个维度:

  • project:www
  • app:java-demo

另外就是镜像拉取,在哪个仓库去下载,这里建议镜像仓库的项目名称和定义的是一种,避免混了。
重新打个标签,并传到私有镜像仓库中。

  1. [root@k8s-master java-demo]# docker tag 192.168.30.24/library/java-demo 192.168.30.24/tomcat-java-demo/java-demo
  2. [root@k8s-master java-demo]# docker push 192.168.30.24/tomcat-java-demo/java-demo:latest

镜像地址也改一下。

  1. imagePullSecrets:
  2. - name: registry-pull-secret
  3. containers:
  4. - name: tomcat
  5. image: 192.168.30.24/tomcat-java-demo/java-demo:latest

现在开始创建yaml。
创建项目的命名空间。

  1. [root@k8s-master java-demo]# vim namespace.yaml
  2. apiVersion: v1
  3. kind: Namespace
  4. metadata:
  5. name: test
  6. [root@k8s-master java-demo]# kubectl create -f namespace.yaml
  7. namespace/test created
  8. [root@k8s-master java-demo]# kubectl get ns
  9. NAME STATUS AGE
  10. default Active 22h
  11. kube-node-lease Active 22h
  12. kube-public Active 22h
  13. kube-system Active 22h
  14. test Active 5s

创建一个secret来保证Harbor镜像仓库的认证信息,这里一定要写上项目的命名空间。

  1. [root@k8s-master java-demo]# kubectl create secret docker-registry registry-pull-secret --docker-username=admin --docker-password=Harbor12345 --docker-email=111@qq.com --docker-server=192.168.30.24 -n test
  2. secret/registry-pull-secret created
  3. [root@k8s-master java-demo]# kubectl get ns
  4. NAME STATUS AGE
  5. default Active 23h
  6. kube-node-lease Active 23h
  7. kube-public Active 23h
  8. kube-system Active 23h
  9. test Active 6m39s
  10. [root@k8s-master java-demo]# kubectl get secret
  11. NAME TYPE DATA AGE
  12. default-token-2vtgm kubernetes.io/service-account-token 3 23h
  13. registry-pull-secret kubernetes.io/dockerconfigjson 1 46s
  14. [root@k8s-master java-demo]# vim deployment.yaml
  15. apiVersion: apps/v1beta1
  16. kind: Deployment
  17. metadata:
  18. name: tomcat-java-demo
  19. namespace: test
  20. spec:
  21. replicas: 3
  22. selector:
  23. matchLabels:
  24. project: www
  25. app: java-demo
  26. template:
  27. metadata:
  28. labels:
  29. project: www
  30. app: java-demo
  31. spec:
  32. imagePullSecrets:
  33. - name: registry-pull-secret
  34. containers:
  35. - name: tomcat
  36. image: 192.168.30.24/tomcat-java-demo/java-demo:latest
  37. imagePullPolicy: Always
  38. ports:
  39. - containerPort: 8080
  40. name: web
  41. protocol: TCP
  42. resources:
  43. requests:
  44. cpu: 0.5
  45. memory: 1Gi
  46. limits:
  47. cpu: 1
  48. memory: 2Gi
  49. livenessProbe:
  50. httpGet:
  51. path: /
  52. port: 8080
  53. initialDelaySeconds: 60
  54. timeoutSeconds: 20
  55. readinessProbe:
  56. httpGet:
  57. path: /
  58. port: 8080
  59. initialDelaySeconds: 60
  60. timeoutSeconds: 20
  61. [root@k8s-master java-demo]# kubectl get pod -n test
  62. NAME READY STATUS RESTARTS AGE
  63. tomcat-java-demo-6d798c6996-fjjvk 1/1 Running 0 2m58s
  64. tomcat-java-demo-6d798c6996-lbklf 1/1 Running 0 2m58s
  65. tomcat-java-demo-6d798c6996-strth 1/1 Running 0 2m58s

另外就是暴露一个Service,这里的标签也要保持一致,不然找不到相应的标签就提供不了服务,这里应该使用Ingress来访问发布,直接使用ClusterIP就可以。

  1. [root@k8s-master java-demo]# vim service.yaml
  2. apiVersion: v1
  3. kind: Service
  4. metadata:
  5. name: tomcat-java-demo
  6. namespace: test
  7. spec:
  8. selector:
  9. project: www
  10. app: java-demo
  11. ports:
  12. - name: web
  13. port: 80
  14. targetPort: 8080
  15. [root@k8s-master java-demo]# kubectl get pod,svc -n test
  16. NAME READY STATUS RESTARTS AGE
  17. pod/tomcat-java-demo-6d798c6996-fjjvk 1/1 Running 0 37m
  18. pod/tomcat-java-demo-6d798c6996-lbklf 1/1 Running 0 37m
  19. pod/tomcat-java-demo-6d798c6996-strth 1/1 Running 0 37m
  20. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  21. service/tomcat-java-demo ClusterIP 10.1.175.191 <none> 80/TCP 19s

测试访问项目,是可以的,现在要通过ingress发布出去。

  1. [root@k8s-master java-demo]# curl 10.1.175.191
  2. <!DOCTYPE html>
  3. <html>
  4. <head lang="en">
  5. <meta charset="utf-8">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <title>把美女带回家应用案例</title>
  8. <meta name="description" content="把美女带回家应用案例">
  9. <meta name="keywords" content="index">

现在部署一个ingress-nginx的控制器,这个网上都可以找到,官方也有,这里是按DaemonSet的方式去部署的,所以每个节点都会跑一个控制器。

  1. [root@k8s-master java-demo]# kubectl get pod -n ingress-nginx
  2. NAME READY STATUS RESTARTS AGE
  3. nginx-ingress-controller-g95pp 1/1 Running 0 3m6s
  4. nginx-ingress-controller-wq6l6 1/1 Running 0 3m6s

发布应用

这里注意两点,一个是网站域名,一个是Service的命名空间。

  1. [root@k8s-master java-demo]# kubectl get pod,svc -n test
  2. NAME READY STATUS RESTARTS AGE
  3. pod/tomcat-java-demo-6d798c6996-fjjvk 1/1 Running 0 53m
  4. pod/tomcat-java-demo-6d798c6996-lbklf 1/1 Running 0 53m
  5. pod/tomcat-java-demo-6d798c6996-strth 1/1 Running 0 53m
  6. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  7. service/tomcat-java-demo ClusterIP 10.1.175.191 <none> 80/TCP 16m
  8. [root@k8s-master java-demo]# vim service.yaml
  9. [root@k8s-master java-demo]# kubectl create -f ingress.yaml
  10. apiVersion: extensions/v1beta1
  11. kind: Ingress
  12. metadata:
  13. name: tomcat-java-demo
  14. namespace: test
  15. spec:
  16. rules:
  17. - host: java.maidikebi.com
  18. http:
  19. paths:
  20. - path: /
  21. backend:
  22. serviceName: tomcat-java-demo
  23. servicePort: 80

这边是测试的,所以绑定本地的hosts来进行访问。在hosts文件里面加入域名和节点IP就能访问到项目了。
Kubernetes部署应用的操作流程 - 图8