[Docker 學習筆記] ENTRYPOINT 和 CMD 的分別和用法

Dockerfile 寫起來相信大家都有一個疑問, ENTRYPOINT 和 CMD 的分別是什麼?

根據 Docker 的官方文檔

An ENTRYPOINT allows you to configure a container that will run as an executable.

The main purpose of a CMD is to provide defaults for an executing container.

看完也不太懂, 繼續向下看

Both CMD and ENTRYPOINT instructions define what command gets executed when running a container. There are few rules that describe their co-operation.

  1. Dockerfile should specify at least one of CMD or ENTRYPOINT commands.
  2. ENTRYPOINT should be defined when using the container as an executable.
  3. CMD should be used as a way of defining default arguments for an ENTRYPOINT command or for executing an ad-hoc command in a container.
  4. CMD will be overridden when running the container with alternative arguments.

結論

簡單直接, ENTRYPOINT 是 Image 運行時 Container 要運行的 Executable
而 CMD 是 ENTRYPOINT 預設的 Argument (參數), 執行時可以被命令行取代

舉個例子, 這個 Dockerfile
運行起來

# Ping 127.0.0.1
docker run test
# Ping 8.8.8.8
docker run test 8.8.8.8

注意事項

1. ENTRYPOINT 和 CMD 都有兩個格式 (JSON Array 和 shell), 官方文檔舉的例子
其中一個用了 shell 格式的話,
紅字部分, CMD 被忽略了, 無法達到我們預期的效果
藍字部分, /bin/sh -c 亂入了, 會令執行起來添加多了一個 bash 進程, PID 不是 1

簡單說, 用 JSON Array 格式就不會錯了

No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

2. ENTRYPOINT 和 CMD 在 Dockerfile 忽略不填的話, 會繼承母 Image 的數值

3. 填寫 ENTRYPOINT 必須同時填寫 CMD, 因為重寫 ENTRYPOINT 會清空 CMD 數值

命令懶人包

# 直接運行 (套用預設 ENTRYPOINT + CMD)
docker run test

# 修改 CMD 運行 (只套用預設 ENTRYPOINT)
docker run test 8.8.8.8

# 修改 ENTRYPOINT 運行 (只套用預設 CMD, 無法這樣使用!)
# docker run --entrypoint=nslookup test

# 修改 ENTRYPOINT + CMD 運行
docker run --entrypoint=nslookup test 8.8.8.8

另外 Override ENTRYPOINT 的話不能直接在 ENTRYPOINT 提供 Argument
需要 Argument 的話要再在後面 CMD 的位置提供

參考: https://medium.com/@oprearocks/how-to-properly-override-the-entrypoint-using-docker-run-2e081e5feb9d

 

[Docker] PHP LibXL integration on Docker Image (Ubuntu 18.04)

Compile LibXL extension for PHP 7.2 @ Ubuntu 18.04, using Docker multi-stage build

Dockerfile

FROM ubuntu:18.04 as build

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y php7.2-dev libxml2-dev git wget

RUN wget http://www.libxl.com/download/libxl-lin-3.8.5.tar.gz && \
tar -zxv -f libxl-lin-3.8.5.tar.gz && \
cd libxl-3.8.5.0/ && \
cp lib64/libxl.so /usr/lib/libxl.so && \
mkdir -p /usr/include/libxl_c/ && \
cp include_c/* /usr/include/libxl_c/

RUN git clone https://github.com/Jan-E/php_excel.git -b php7-issue241 && \
cd php_excel && \
phpize && \
./configure --with-php-config=/usr/bin/php-config --with-libxl-incdir=/usr/include/libxl_c/ --with-libxml-dir=/usr/include/libxml2/ --with-excel && \
make

FROM ubuntu:18.04

# Install your PHP stack 
[...]

# Install LibXL
COPY --from=build /php_excel/modules/excel.so /usr/lib/php/20170718/

COPY --from=build /libxl-3.8.5.0/lib64/libxl.so /usr/lib/libxl.so

COPY ./docker/excel.ini /etc/php/7.2/mods-available/

RUN phpenmod excel

# Other stuff
[...]

/docker/excel.ini

; priority=30
extension=excel.so

[excel]
excel.license_name="Tiger Fok"
excel.license_key="linux-xxxxxxxxxxxxxxxxxxxxxxxxxxx"
excel.skip_empty=0

[Docker 學習筆記] Run/Compose/Swarm Mode 幾個運行方式基本概念

這裡不打算談什麼是 Docker, 如何打包 Image 之類
網路上已經太多太多相關教學了
所以第一篇就直接說幾個 Docker 的運行方式的基本概念吧
晚點再寫幾個命令的懶人包 (給自己 Copy XD)

docker build, run 與 Dockerfile

Dockerfile 用於 Build 自己的 Image
或者應該說, 基於別人的 Image 修改時也需要使用

# 以當前目錄的 Dockerfile Build Image “myapp”
docker build -t myapp .

# 運行 Image
docker run myapp

# 運行 containous/whoami Image 並對外開放 80 Port
docker run -p 80:80 containous/whoami

docker-compose 與 docker-compose.yml

docker-compose 是一個基於 Python 的工具
主要用來把多個 Container 綁起來一起運行
還有節省長長的命令行參數

# 以當前目錄的 docker-compose.yml 執行一個/多個 Container
docker-compose up

# 以當前目錄的 docker-compose.yml Build 裡面所有 Images
docker-compose build

Docker Swarm Mode, Service 及 Stack

重要: 這裡談的不是已經廢棄的產品 “Docker Swarm”!!
只差個 Mode 字差很多 網路上找到的教學都要確定是 Swarm Mode 再看

Docker Swarm Mode 是 Docker 內建的 Container Orchestration 功能
嗯… 這裡也不打算解釋了 簡單來說
它大概是能把一個 Image 同時運行幾個 Container (在一台/多台 Host 上)
然後自動管理 + 負載平衡的機制

docker service 好比 docker run
是直接把一個 Image 以 Swarm Mode 運行的方法

# 在 Swarm 上運行 myapp
docker service create myapp
# 在 Swarm 上運行 containous/whoami 並對外開放 80 Port
docker service create -p 80:80 containous/whoami

docker stack 好比 docker-compose
是把多個 Service 以 docker-compose.yml 綁起來一起運行的方法
# 在 Swarm 上以 docker-compose.yml 運行 myapp-stack
docker stack deploy myapp-stack --compose-file docker-compose.yml

這裡的 docker-compose.yml 跟 docker-compose.yml 格式是通用的
但也有 Swarm Mode 和 Docker Compose 專用的選項, 這之後再說了