Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layered Spring Boot Docker images #292

Open
uniquejava opened this issue Apr 3, 2020 · 2 comments
Open

Layered Spring Boot Docker images #292

uniquejava opened this issue Apr 3, 2020 · 2 comments
Labels

Comments

@uniquejava
Copy link
Owner

uniquejava commented Apr 3, 2020

阅读前必读:

  1. Best practices for writing Dockerfiles最佳实践
  2. Docker image为什么要分层

当前的spring boot Dockerfile配置

Dockerfile

FROM adoptopenjdk/openjdk8:ubi-jre
EXPOSE 9090
RUN mkdir /opt/app
ADD target/myapp.jar /opt/app/app.jar
ENTRYPOINT [ "sh", "-c", "java -Dspring.profiles.active=dev -jar /opt/app/app.jar" ]

Tips:spec中的command能覆盖Dockerfile中的ENTRYPOINT.

k8s-myapp-dev.yaml

spec:
  restartPolicy: Always
  containers:
    - image: jp.icr.io/myorg/myapp:1.0.15
      imagePullPolicy: Always
      command:
        [
          "sh",
          "-c",
          "java -Dspring.profiles.active=dev -jar /opt/app/app.jar",
        ]
      name: myapp
      volumeMounts:
        - name: logs-persistent-storage
          mountPath: /logs

当前build和push的方式

详见: https://cloud.ibm.com/kubernetes/registry/main/start

# Log in to your IBM Cloud account.
ibmcloud login -a https://cloud.ibm.com --sso

# Ensure that you're targeting the correct IBM Cloud Container Registry region.
ibmcloud cr region-set ap-north

# Choose a name for your first namespace, and create that namespace.
ibmcloud cr namespace-add <my_namespace>

# Log your local Docker daemon into the IBM Cloud Container Registry.
ibmcloud cr login

# 查看当前有哪些image (找到最新image的版本号)
ibmcloud cr images

# 做一个更新的image (注意每次将版本号x加1)
export VERSION=1.0.1
# 在本地编译java项目
cd myapp
mvn clean package -DskipTests=true
docker build -t myorg/myapp:$VERSION .

# 打两个tag
docker tag myorg/myapp:$VERSION jp.icr.io/myorg/myapp:$VERSION

# 切换到 Context A
ibmcloud ks cluster config --cluster xxxxxxxxx
# 推送到 A 环境
docker push jp.icr.io/myorg/myapp:$VERSION
# 修改 k8s-myapp-dev.yaml中的版本号
vi ../kubernetes/development/k8s-myapp-dev.yaml
# 重新apply
kubectl apply -f ../kubernetes/development/k8s-myapp-dev.yaml

存在的问题

docker images
docker history myorg/myapp:$VERSION

Dockerfile中的每一条指令构成一个新的layer, 通过docker history命令可以看到 ADD target/myapp.jar 这一步build了一个相当大的image layer(60M)

我们需要将spring boot中不变的dependency单独build成一个独立的image layer。

References

Optimizing Spring Boot apps for Docker

https://blog.jdriven.com/2019/08/layered-spring-boot-docker-images/

@uniquejava
Copy link
Owner Author

uniquejava commented Apr 3, 2020

A better Dockerfile

每一步的含义见: https://spring.io/blog/2018/11/08/spring-boot-in-a-container

Dockerfile

FROM adoptopenjdk/openjdk8:ubi-jre

EXPOSE 9090

RUN mkdir /app

ARG DEPENDENCY=target/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes /app

ENTRYPOINT [ "sh", "-c", "java ${JAVA_OPTS} -cp app:app/lib/* com.xxx.MyAwesomeApplication ${0} ${@}" ]

像这样打包:

mvn clean package -DskipTests=true
mkdir target/dependency
(cd target/dependency; tar -zxf ../*.jar)
docker build -t myorg/myapp:$VERSION .

新的yaml (通过yaml向docker传递JAVA_OPTS)

参考: Define Environment Variables for a Container

    spec:
      restartPolicy: Always
      containers:
        - image: jp.icr.io/myorg/myapp:1.0.16
          imagePullPolicy: Always
          env:
            - name: JAVA_OPTS
              value: "-Dspring.profiles.active=dev"
          name: myapp

完整的过程

# Log your local Docker daemon into the IBM Cloud Container Registry.
ibmcloud cr login

# 查看当前有哪些image (找到最新image的版本号)
ibmcloud cr images

# 做一个更新的image (注意每次将版本号x加1)
export VERSION=1.0.1
# 在本地编译java项目, dual layered, 详见 https://spring.io/blog/2018/11/08/spring-boot-in-a-container
cd myapp
mvn clean package -DskipTests=true
mkdir target/dependency
(cd target/dependency; jar -xf ../*.jar)
docker build -t myorg/myapp:$VERSION .

# 打tag
docker tag myorg/myapp:$VERSION jp.icr.io/myorg/myapp:$VERSION

# 切换到 context A
ibmcloud ks cluster config --cluster xxxx
# 推送到 A 集群
docker push jp.icr.io/myorg/myapp:$VERSION
# 修改 k8s-myapp-dev.yaml中的版本号
vi ../kubernetes/development/k8s-myapp-dev.yaml
# 重新apply
kubectl apply -f ../kubernetes/development/k8s-myapp-dev.yaml
# 查看pod状态
kubectl get po
# 查看spring boot启动的日志文件 (网络原因有点卡), 两个pod实例的日志交织在一起
# 10.47.84.37 是node的内部ip地址
../kubernetes/development/nsenter-node.sh 10.47.84.37
=> If you dont see a command prompt, try pressing enter.
=> root@kube-xxx:~#
=> root@kube-xxx:~# tail -f /mnt/myapp/logs/sa.log (查看后台日志文件)
=> root@kube-xxx:~# exit
(按Ctrl + D)
=> logout
=> pod "cyper-nsenter-10.47.84.37" deleted

# tips: 查看当前 k8s 上下文
kubectl config get-contexts

@uniquejava
Copy link
Owner Author

继续优化

mkdir target/dependency
(cd target/dependency; tar -zxf ../*.jar)

写到pom.xml里

详见: https://blog.jdriven.com/2019/08/layered-spring-boot-docker-images/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant