环境准备

需要k8s集群和本地仓库,如果你还没有搭建,建议参考我上面两篇文章Kubernetes集群搭建详细指南为kubernetes创建本地镜像仓库

部署MySQL

首先我们需要创建持久卷和持久卷声明,用来为MySQL挂载存储,不然容器重启数据就丢失了。

创建持久卷和持久卷声明

将以下的yaml声明保存为mysql-pv.yaml,然后执行apply命令。

  1. apiVersion: v1
  2. kind: PersistentVolume
  3. metadata:
  4. name: mysql-01
  5. spec:
  6. capacity:
  7. storage: 10Gi
  8. accessModes:
  9. - ReadWriteOnce
  10. persistentVolumeReclaimPolicy: Retain
  11. storageClassName: mysql
  12. nfs:
  13. path: /nfs/mysql
  14. server: 192.168.18.131
  15. ---
  16. apiVersion: v1
  17. kind: PersistentVolumeClaim
  18. metadata:
  19. name: mysql-pv-claim
  20. spec:
  21. storageClassName: mysql
  22. accessModes:
  23. - ReadWriteOnce
  24. resources:
  25. requests:
  26. storage: 10Gi
kubectl apply -f mysql-pv.yaml

查看pv状态

[root@k8s-master01 springboot-mysql]# kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                    STORAGECLASS   REASON   AGE
mysql-01         10Gi       RWO            Retain           Bound       default/mysql-pv-claim   mysql                   28s

部署MySQL 5.6

这里选择了MySQL5.6的版本,你也可以换成其他的。
将以下的yaml声明保存为mysql-deployment.yaml,然后执行apply命令。
我们创建MySQL的同时创建了Service,Service为集群中的容器通信提供了服务发现功能。

apiVersion: apps/v1
apiVersion: v1
kind: Service
metadata:
  name: mysql-stand-alone
  labels:
    app: mysql-stand-alone
spec:
  type: NodePort
  ports:
  - name: mysql-stand-alone
    port: 3306
    targetPort: 3306
    nodePort: 30008
  selector:
    app: mysql-stand-alone
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-stand-alone
spec:
  selector:
    matchLabels:
      app: mysql-stand-alone
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql-stand-alone
    spec:
      containers:
        - image: mysql:5.6
          name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: Sgy@97
          ports:
            - containerPort: 3306
              name: mysql
          volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
      volumes:
        - name: mysql-persistent-storage
          persistentVolumeClaim:
            claimName: mysql-pv-claim

部署

kubectl apply -f mysql-deployment.yaml

查看部署结果:

[root@k8s-master01 springboot-mysql]#  kubectl get pods -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP                NODE         NOMINATED NODE   READINESS GATES
mysql-stand-alone-775f8c4fb5-4dldq    1/1     Running   0          60s   192.168.85.226    k8s-node01   <none>           <none>

查看svc: mysql-stand-alone

[root@k8s-master01 springboot-mysql]#  kubectl get svc
NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes           ClusterIP   10.20.0.1      <none>        443/TCP          13h
mysql-read           NodePort    10.20.60.83    <none>        3306:30036/TCP   12h
mysql-stand-alone    NodePort    10.20.1.21     <none>        3306:30008/TCP   23s
mysql-writeandread   NodePort    10.20.119.83   <none>        3306:30006/TCP   12h

使用navicat进行远程连接

image.png
image.png

部署spring-boot项目

在项目根目录创建Dockerfile

# 该镜像需要依赖的基础镜像
FROM openjdk:8-jre-alpine
# 声明服务运行在8088端口
EXPOSE 11000
# 指定维护者的名字
MAINTAINER shenguangyang
# 环境变量,应用名字,注意修改ENTRYPOINT中的名字
ENV APP_NAME=demo

# 将构建出的主包赋值到指定镜像目录中
RUN mkdir -p /home/admin/$APP_NAME/logs /home/admin/$APP_NAME/bin /home/admin/$APP_NAME/target
COPY $APP_NAME.jar /home/admin/$APP_NAME/target/$APP_NAME.jar

ENTRYPOINT ["java" , "-jar" , "/home/admin/demo/target/demo.jar"]

修改配置文件

如下,其中url的第二个mysql-stand-alone即为我们之前创建MySQL的service名称。MySQL的username和password则通过环境变量的形式读取,实际生产环境更推荐用Secret来加密存储MySQL的用户名和密码。

spring:
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
  servlet:
    multipart:
      enabled: true
      max-file-size: 5120MB
      max-request-size: 5120MB
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://mysql-stand-alone:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&autoReconnect=true
    username: ${MYSQL_USERNAME}
    password: ${MYSQL_PASSWORD}

构建镜像并推送到私有仓库

#!/bin/bash
APP_GROUP="app"
APP_NAME="demo"
APP_VERSION="v2.0"
HARBOR_URL="192.168.18.131:5000/spring-boot-k8s-app"
APP=$HARBOR_URL"/"$APP_GROUP"/"$APP_NAME":"$APP_VERSION
### docker rmi这步一定要有,如果不删除旧镜像,当新镜像打包的时候会产生none镜像; ###
echo "删除旧镜像"
docker rmi $APP

### 镜像打包 ###
echo "镜像打包"
docker build -f Dockerfile -t $APP .

echo "登录harbor"
docker login 192.168.18.131:5000 -u admin -p Harbor12345

### 推送镜像
echo "推送镜像"
docker push $APP

### 将镜像提交成tar ###
#docker save -o $APP_NAME ".tar" $APP

将jar包以及Dockerfile以及本脚本放在同一个文件夹下,然后执行本脚本进行推送到私有仓库
image.png

创建资源定义文件yaml

在项目根目录下创建deploy文件夹,按照如下创建spring-boot-deployment.yaml文件,并放到deploy文件夹下。根据你的实际集群环境,你需要替换192.168.18.128:5000为自己的镜像仓库。

kind: Service
apiVersion: v1
metadata:
  name: spring-boot-k8s-app-service
spec:
  type: NodePort
  selector:
    app: spring-boot-k8s-app
  ports:
    - protocol: TCP
      targetPort: 11000
      port: 11000
      nodePort: 32082
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-k8s-app-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: spring-boot-k8s-app
  template:
    metadata:
      labels:
        app: spring-boot-k8s-app
    spec:
      containers:
        - name: spring-boot-k8s-app-controller
          imagePullPolicy: Always
          image: 192.168.18.131:5000/spring-boot-k8s-app/app/demo:v2.0
          ports:
            - containerPort: 11000
          env:
            - name: MYSQL_PORT
              value: '3306'
            - name: MYSQL_USERNAME
              value: root
            - name: MYSQL_PASSWORD
              value: Sgy@97
      imagePullSecrets:
        - name: myregistrysecret

开始部署

[root@k8s-master01 springboot-mysql]# kubectl apply -f spring-boot-k8s-app-deployment.yaml
service/spring-boot-k8s-app-service created
deployment.apps/spring-boot-k8s-app-deployment created

查看部署状态:发现有1个app调度到node2节点:

[root@k8s-master01 springboot-mysql]# kubectl get pod -l app=spring-boot-k8s-app -o wide
NAME                                              READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
spring-boot-k8s-app-deployment-67fcbd4746-kcvt5   1/1     Running   0          14m   192.168.85.239   k8s-node01   <none>           <none>
spring-boot-k8s-app-deployment-67fcbd4746-wzdpn   1/1     Running   0          14m   192.168.85.249   k8s-node01   <none>           <none>
spring-boot-k8s-app-deployment-67fcbd4746-xh8n4   1/1     Running   0          14m   192.168.58.225   k8s-node02   <none>           <none>

外部访问

由于当前springboot项目对应的Service为NodePort类型,那么它可以从集群外部通过NodeIp和NodePort进行访问。直接通过宿主机浏览器访问http://192.168.18.132:32082/地址即可看到效果。
image.png

数据库
image.png

参考文献

Harbor企业级私有Docker镜像仓库部署:https://www.yuque.com/yanggev587/qwpqbe/qluzbn
K8S之存储Secret详解:https://www.yuque.com/yanggev587/qwpqbe/wyol7k