2019年1月1日 星期二

淺談 Dockerfile

前陣子在玩 Dockerfile 想做成自動化打包 + 測試,在這過程中深刻體認到... Docker 需要注意的地方真不少,三天時間每當打包好後的 10 到 20分鐘,就可以找到數個問題,後續的我就浮沉在尋找問題跟解決問題之間。整理這篇文章作為經驗分享期許能幫助到更多人。

什麼是 Dockerfile

在開始講會碰到的一些問題前,要先知道 Dockerfile 其實是一個檔案用於撰寫 Docker Image 的建置腳本,編寫好後使用 Docker build -t {repository name} . 指令,這時 Docker 就會為我們打造一個專屬於自己的 Docker Image。
接著可以再執行 docker run -it {repository name},運行起一個被稱之為 Container 的環境,在環境中有一個與本機隔絕獨立的環境,至於這樣有什麼好處小編不在此多講,試想一個輕量化可通過指令控制的 VM 能帶來哪些好處,那大致也不會差得太遠了。

認識 Dockerfile

既然知道是一種腳本那就會有語法,讓我們用一個範例來認識 Dockerfile

範例

這是一個期望用於測試環境用的腳本,所以主要包含 Java, HBase, Maven 和 Proguard 等。(除此之外還包含 SSh 是由於 HBase 會通過通過此工具連線自身喚起服務)
Dockerfile
FROM centos:centos6.10

MAINTAINER CookieTsai

# Add JDK, HBase and Maven tarball file, using ADD will auto unzip the file.
ADD jdk1.7.0_151.tar.gz /opt/
ADD apache-maven-3.5.4-bin.tar.gz proguard5.3.3.tar.gz /opt/
ADD hbase-1.2.9-local.tar.gz /opt/

# 1. Install sshd and vim and making ssh non-ask
# 2. Setting ssh login without password and close firewall
# 3. Install JDK, HBase and Maven
RUN yum -y install openssh* vim-enhanced \
    && echo "StrictHostKeyChecking no" >> /etc/ssh/ssh_config \
    && ssh-keygen -t rsa -f ~/.ssh/id_rsa -P "" \
    && cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys \
    && chmod 600 ~/.ssh/authorized_keys \
    && service iptables stop && chkconfig iptables off \
    && ln -s /opt/jdk1.7.0_151 /opt/java \
    && ln -s /opt/apache-maven-3.5.4 /opt/maven \
    && ln -s /opt/proguard5.3.3 /opt/proguard \
    && ln -s /opt/hbase-1.2.9 /opt/hbase

ENV USER=root \
    JAVA_HOME=/opt/java \
    MAVEN_HOME=/opt/maven \
    HBASE_HOME=/opt/hbase \
    PROGUARD_HOME=/opt/proguard \
    PATH=/opt/proguard/bin:/opt/hbase/bin:/opt/maven/bin:/opt/java/bin:$PATH

# 1. Install nodejs's nvm
# 2. Using npm install newman and newman-reporter-html
RUN curl -s -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.2/install.sh | bash \
    && source /root/.nvm/nvm.sh \
    && nvm install v10.14.2 \
    && nvm alias default v10.14.2 \
    && nvm use default \
    && npm install -g newman \
    && npm install -g newman-reporter-html

EXPOSE 22 2181 8090 60000 60010 60020 60030

# Set root's setting
ADD startup.sh /startup.sh
RUN cat /startup.sh >> /root/.bashrc && echo "root:root" | chpasswd

CMD ["/bin/bash"]
startup.sh
if [ -d "$HBASE_HOME" ]; then
  # Start SSH Server
  service sshd start

  # Set Reginservers
  HOST_NAME=`hostname`
  sed -i "s/localhost/$HOST_NAME/" /opt/hbase/conf/hbase-site.xml
  echo $HOST_NAME > /opt/hbase/conf/regionservers

  # Start HBase
  start-hbase.sh
fi

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

語法解析

  • FROM:指要以哪一個 Image 作為基底
  • MAINTAINER:註明主要的維護者
  • ADD:將指定路徑的目錄或檔案放入 Image 的指定目錄中
  • RUN:建置時會執行此指令後的語法
  • ENV:設定系統內的環境變數
  • EXPOSE:設定給使用者知道哪些 PORT 有開放
  • CMD:設定當啟動時預設執行的命令

註解

  1. 多數語法指令是相互獨立,建議使用絕對路徑或直接宣告
    ADD /opt/sample.tar.gz /opt
    RUN cd /opt
    RUN tar -zxvf sample.tar.gz # 與前一指令相互獨立,此執行結果為找不到檔案
  2. 每一個指令 (如:RUN、ADD) 執行後會有一次 Commit
  3. FROM 指令的預設來源為 Docker hub
  4. ADD 指令在指定壓縮檔案加入時,如果有支援的情況下會自動解壓縮
  5. 除非確定要解壓縮其他時候都可以利用 COPY 指令取代來 ADD

其他

  1. Docker Image 最多只能有 127 個 Parents
  2. 使用 docker run 時並非是真的使用 root 身份完成登入必須當心
  3. 使用 docker run -it {image name} 時是可以利用 .bashrc 執行預設指令