動機

看看寫Dockerfile的注意事項

目標

  1. 減小Image的大小
  2. 盡量使用cache
  3. 讓環境一致

COPY或RUN一次就會多一層layer,所以

把可以整合在同一句的RUN整合在同一句

Before

RUN apt update
RUN apt install -y ...

After

RUN apt update && apt install -y ...

只COPY需要的東西

Before

COPY . /app

After

COPY file1 file2 ... /app

把不常變動的放前面

只要docker看到這句的cache失效 就會把後面的所有指令都重跑一遍 Before

COPY file1 file2 ... /app
RUN apt update && apt install -y ...

After

RUN apt update && apt install -y ...
COPY file1 file2 ... /app

減少cache,只放真的需要的東西

移除不需要的dep & 清除apt快取

Before

RUN apt update && apt install -y ... vim

After

RUN apt update && apt install -y --no-install-recommends ... && rm -rf /var/lib/apt/lists/* 
COPY file1 file2 ... /app

讓環境一致

如果有現成的就直接用,同時指定版本

Before

RUN apt update && apt install -y openjdk8 vim

After

FROM openjdk:8
COPY file1 file2 ... /app

剛剛好的權限

直接看例子

FROM maven:3.6.3-jdk-11 AS builder
WORKDIR /workdir/server
COPY pom.xml /workdir/server/pom.xml
RUN mvn dependency:go-offline

RUN mvn package

FROM openjdk:11-jre-slim
RUN addgroup -S java && adduser -S javauser -G java
USER javauser

EXPOSE 8080
COPY --from=builder /workdir/server/target/project-0.0.1-SNAPSHOT.jar /project-0.0.1-SNAPSHOT.jar

CMD ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/project-0.0.1-SNAPSHOT.jar"]

區分不同的step(就是替dockerfile抽象)

multi-stege build (Docker 17.05後)

FROM openjdk:8 AS builder
...

FROM openjdk:8-jre-alpine
COPY --from=builder file1 file2 /app
CMD ["java", "-jar", "/app/app.jar"]

這個其實就是在一般PL會看到的副程式

不過因為Dockerfile沒有控制結構(條件判斷與迴圈) 所以沒有重複呼叫某塊code產生資料的需要 只要跑完要的資料就會在image中 因此只要有辦法碰到需要的Image就好 所以才有這種東西

不只是用自己的image,用其他的image也是ok的

COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

只想build到某一層的Image也沒問題

docker build --target builder -t alexellis2/href-counter:latest .

Ref

source1 source2 multi-stege build