Java程序製做Docker Image推薦方案

原文地址html

本文源代碼是一個spring-boot應用(在 https://github.com/chanjarste... ),不過本例子適用於全部Java應用。java

要求

這裏先給出一些Docker Image製做的要求,以後咱們再看怎麼作。mysql

  1. 製做過程要融合在項目構建過程當中
  2. 使用官方Image做爲基礎Image
  3. 設定正確的時區
  4. Container內的程序以非root用戶啓動
  5. 指定Web程序的端口
  6. 可以傳遞JVM參數、Java System Properties、程序自定義的參數

下面具體講一下具體怎麼作到以上幾點:git

製做過程要融合在項目構建過程當中

這裏推薦使用Spotify的dockerfile-maven-plugin,理由是這個plugin用起來最簡單且容易掌握。github

該plugin的本質上是你寫一個Dockerfile(關於Dockerfile的具體寫法請參照官方文檔),這個plugin把一些參數傳遞進去來幫助你構建Docker Image。spring

所以只要你會寫Dockerfile,就會使用這個plugin,它沒有加入任何額外的概念。sql

使用官方Image做爲基礎Image

Java的基礎鏡像應該在openjdk repository裏尋找,而不是在已通過時的java repository裏找。docker

openjdk repository提供了各類各樣的image tags看起來眼花繚亂,可是本質上來講就這麼幾個:shell

  • openjdk:<version>
  • openjdk:<version>-slim
  • openjdk:<version>-alpine

關於<version>通常來講指定大版本號就好了,好比你能夠在Dockerfile這樣寫:數據庫

FROM openjdk:8-alpine

從尺寸上來說,alpine最小、slim稍大、默認的最大。因此應該儘量的使用alpine版本的,若是發現程序的運行環境缺乏某些東西,那麼嘗試用slim版本或者默認版本。就目前的經驗來說:

  • 若是須要操做系統字體庫,那麼就得使用slim版本或者默認版本。須要操做系統字體庫的程序例如:圖片驗證碼、PDF導出。
  • 若是須要某些Linux標準的動態/靜態鏈接庫,那麼在alpine版本不行的狀況下,嘗試slim版本或默認版本。由於alpine版本是一個及其精簡的Linux,它刪除了不少東西。

設定正確的時區

幾乎全部的Docker Image的時區都是UTC,咱們須要給咱們本身製做的Docker Image設定時區:

ENV TZ=Asia/Shanghai
RUN set -eux; \
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime; \
    echo $TZ > /etc/timezone

若是是alpine系列的則要安裝tzdata:

ENV TZ=Asia/Shanghai
RUN set -eux; \
    apk add --no-cache --update tzdata; \
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime; \
    echo $TZ > /etc/timezone

關於數據庫時區的相關內容能夠見:

Container內的程序以非root用戶啓動

在Docker Image內部,咱們應該使用非root用戶啓動程序,這須要新建用戶。

若是你用的是openjdk:<version>-alpine新建用戶命令是這樣的:

RUN set -eux; \
    addgroup --gid 1000 java-app; \
    adduser -S -u 1000 -g java-app -h /home/java-app/ -s /bin/sh -D java-app;

若是你用的是openjdk:<version>-slim或者openjdk:<version>新建用戶命令是這樣的:

RUN set -eux; \
    addgroup --gid 1000 java-app; \
    adduser --system --uid 1000 --gid 1000 --home=/home/java-app/ --shell=/bin/sh --disabled-password java-app;

而後使用Dockerfile USER指令

USER java-app

# 後面的指令就都是以java-app用戶身份執行了

指定Web程序的接口

對於聯網應用而言,必須在Dockerfile中指定暴露的端口,不然該端口沒法映射。

EXPOSE 8080

可以傳遞JVM參數、Java System Properties、程序自定義的參數

咱們須要可以在啓動Docker Image的時候將一些參數傳遞進去:

  • JVM參數
  • Java System Properties
  • 程序啓動參數

這裏就須要參考Dockerfile best practiceDocker ENTRYPOINT了。

樣例項目拆解

目錄結構

全部與程序相關的東西都存放在/home/java-app/下:

/home/java-app
   ├── docker-entrypoint.sh
   ├── lib
   │   └── java-app.jar
   ├── etc
   ├── logs
   └── tmp
  • docker-entrypoint.sh,啓動腳本
  • lib,存放JAR包
  • lib/java-app.jar,程序JAR包
  • etc,存放配置文件
  • logs,存放日誌文件
  • tmp,存放臨時文件

構建Image的方法

mvn clean package dockerfile:build

運行

普通啓動,而後訪問http://localhost:8080

docker run -p 8080:8080 chanjarster/dockerfile-java-examples-1:1.0-SNAPSHOT

設定JVM參數/System Properties,使用JAVA_OPTS環境變量:

docker run -p 8080:8080 -e JAVA_OPTS='-Xmx128M -Xms128M -Dabc=xyz -Ddef=uvw' chanjarster/dockerfile-java-examples-1:1.0-SNAPSHOT

提供程序運行參數,在後面直接添加便可:

docker run -p 8080:8080 chanjarster/dockerfile-java-examples-1:1.0-SNAPSHOT --debug

2018-12-27更新

docker-entrypoint.sh裏啓動Java進程時,使用exec /usr/bin/java ...這種形式,保證進程PID=1,這樣在進程可以在docker stop時收到SIGTERM
詳見:docker stop

參考文檔

相關文章
相關標籤/搜索