kubeasz/docs/practice/java_war_app.md

4.8 KiB
Raw Blame History

JAVA WAR 应用迁移 K8S 实践

初步思路是这样:应用代码与应用配置分离,应用代码打包成 docker 镜像存于内部 harbor 仓库,应用配置使用 configmap 挂载,这样不同的环境只需要修改 configmap 即可部署。

  • 使用 maven 把 java 应用代码打包成 xxx.war
  • 基于 tomcat 镜像和 xxx.war 做成应用 docker 镜像
  • 编写 k8s deployment 文件,在 pod 指定上述应用镜像,同时把应用配置做成 configmap 挂载到 pod 里

经过多次尝试部署发现问题configmap配置是可以挂载上去但是会把目录下其他的文件删掉而且tomcat 目录 webapps/xxxxx/下其他目录也消失了。原来是因为 tomcat 容器完全启动完成后才会解压 war包而 configmap 配置文件是一开始就挂载上去了,导致失败。

  • 调整应用镜像打包过程xxx.war 先解压后再进行应用镜像打包

应用 gitlab CI/CD 集成

  • 在内部gitlab创建项目上传应用java代码同时在项目根目录下新加如下目录和文件配置相应的 gitlab-runner 和 环境变量参数
├── .app.yaml		# k8s deployment 部署模板文件 
├── config.yaml		# k8s configmap 配置模板文件
├── dockerfiles
│   └── Dockerfile	# Dockerfile 文件
├── .gitlab-ci.yml	# gitlab ci 配置文件
└── .ns.yaml		# k8s namespace 和 imagePullSecrets的配置文件

gitlab-ci 文件摘要

variables:
  PROJECT_NS: '$CI_PROJECT_NAMESPACE-$CI_JOB_STAGE'
  APP_NAME: '$CI_PROJECT_NAME-$CI_COMMIT_REF_SLUG'

stages:
  - package
  - beta

job_package:
  stage: package
  tags:
    - package-shell
  only:
    - master
    - /^feature-.*$/
  script:
  - mvn clean install -Dmaven.test.skip=true
  - unzip target/xxxx.war -d dockerfiles/project
  - cd dockerfiles && docker build -t harbor.test.lo/project/$CI_PROJECT_NAME:$CI_PIPELINE_ID .
  - docker login -u $HARBOR_USR -p $HARBOR_PWD harbor.test.lo
  - docker push harbor.test.lo/project/$CI_PROJECT_NAME:$CI_PIPELINE_ID
  - docker logout harbor.test.lo

job_push_beta:
  stage: beta
  tags:
    - beta-shell
  only:
    - master
    - /^feature-.*$/
  when: manual
  script:
  # 替换beta环境的参数配置
  - sed -i "s/PROJECT_NS/$PROJECT_NS/g" config.yaml .app.yaml .ns.yaml
  - sed -i "s/TemplateProject/$APP_NAME/g" config.yaml .app.yaml
  - sed -i "s/DB_HOST/$BETA_DB_HOST/g" config.yaml
  - sed -i "s/DB_PWD/$BETA_DB_PWD/g" config.yaml
  - sed -i "s/APP_REP/$BETA_APP_REP/g" .app.yaml
  - sed -i "s/ProjectImage/$CI_PROJECT_NAME:$CI_PIPELINE_ID/g" .app.yaml
  #
  - mkdir -p /opt/kube/$PROJECT_NS/$APP_NAME
  - cp -f .ns.yaml config.yaml .app.yaml /opt/kube/$PROJECT_NS/$APP_NAME
  - kubectl --kubeconfig=/etc/.beta/config apply -f .ns.yaml
  - kubectl --kubeconfig=/etc/.beta/config apply -f config.yaml
  - kubectl --kubeconfig=/etc/.beta/config apply -f .app.yaml

# 生产部署与beta环境类同这里省略

Dockerfile 编写

FROM tomcat:8.5.33-jre8-alpine

COPY . /usr/local/tomcat/webapps/

# 设置tomcat日志使用的时区
RUN sed -i 's/^JAVA_OPTS=.*webresources\"$/JAVA_OPTS=\"$JAVA_OPTS -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Duser.timezone=GMT+08\"/g' /usr/local/tomcat/bin/catalina.sh

k8s deployment 配置举例

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: TemplateProject
  namespace: PROJECT_NS
spec:
  replicas: APP_REP
  template:
    metadata:
      labels:
        run: TemplateProject
    spec:
      containers:
      - name: TemplateProject
        image: harbor.test.lo/project/ProjectImage
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: db-config
          mountPath: "/usr/local/tomcat/webapps/project/xxxx/yyyy/config/datasource.properties"
          subPath: datasource.properties
      imagePullSecrets:
      - name: projectkey1
      volumes:
      - name: db-config
        configMap:
          name: TemplateProject-config
          defaultMode: 0640
          items:
          - path: datasource.properties
            key: datasource.properties

---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: TemplateProject
  name: TemplateProject
  namespace: PROJECT_NS
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    run: TemplateProject
  sessionAffinity: None

k8s configmap 配置举例

apiVersion: v1
kind: ConfigMap
metadata:
  name: TemplateProject-config
  namespace: PROJECT_NS
data:
  datasource.properties: |
    dataSource.maxIdle = 5
    dataSource.maxActive = 41
    dataSource.driverClassName = com.mysql.jdbc.Driver
    dataSource.url = jdbc:mysql://DB_HOST:8066/project?useUnicode=true&characterEncoding=utf-8
    dataSource.username = username
    dataSource.password = DB_PWD