1. 程式人生 > 其它 >Blog.082 Dockerfile 映象定製與構建

Blog.082 Dockerfile 映象定製與構建

本章目錄

1. 使用 Dockerfile 定製映象
2. Dockerfile 指令詳解
  2.1 FROM:指定基礎映象
  2.2 RUN:執行命令
  2.3 COPY:複製檔案
  2.4 ADD:更高階的複製檔案
  2.5 CMD:容器啟動命令
  2.6 ENTRYPOINT:指定執行時要執行的命令
  2.7 ENV:設定環境變數
  2.8 ARG:構建引數
  2.9 VOLUME:定義資料卷目錄
  2.10 EXPOSE:宣告埠
  2.11 WORKDIR:指定工作目錄
  2.12 USER:指定當前使用者
  2.13 HEALTHCHECK:健康檢查
  2.14 ONBUILD 命令


3. 映象構建例項
  3.1 Nginx 映象
  3.2 Tomcat 映象
  3.3 SSHD 映象
  3.4 Systemctl 映象
  3.5 MySQL 映象

1. 使用 Dockerfile 定製映象

    映象的定製實際上就是定製每一層所新增的配置、檔案。如果我們可以把每一層修改、安裝、構建、操作的命令都寫入一個指令碼,用這個指令碼來構建、定製映象,那麼無法重複的問題、映象構建透明性的問題、體積的問題就都會解決。這個指令碼就是 Dockerfile

    Dockerfile 是一個文字檔案,其內包含了一條條的指令(Instruction),每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建

    此處以定製 nginx 映象為例,使用 Dockerfile 來定製。

    在一個空白目錄中,建立一個文字檔案,並命名為 Dockerfile:

1 mkdir mynginx
2 cd mynginx
3 touch Dockerfile

    其內容為:

1 FROM nginx
2 RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

    這個 Dockerfile 很簡單,一共就兩行。涉及到了兩條指令, FROM 和 RUN。

    在編寫 Dockerfile 時,有嚴格的格式需要遵循:

  • 第一行必須使用 FROM 指令指明所基於的映象名稱
  • 之後使用 MAINTAINER 指令說明維護該映象的使用者資訊
  • 然後是映象操作相關指令,如RUN指令;每執行一條指令,都會給基礎映象新增新的一層
  • 最後使用CMD指令指定啟動容器時要執行的命令操作


2. Dockerfile 指令詳解
  2.1 FROM:指定基礎映象

    所謂定製映象,那一定是以一個映象為基礎,在其上進行定製。而 FROM 就是指定基礎映象,因此一個 Dockerfile 中 FROM 是必備的指令,並且必須是第一條指令

    除了選擇現有映象為基礎映象外,Docker 還存在一個特殊的映象,名為 scratch 。這個映象是虛擬的概念,並不實際存在,它表示一個空白的映象。

如果你以 scratch 為基礎映象的話,意味著你不以任何映象為基礎,接下來所寫的指令將作為映象第一層開始存在。

    不以任何系統為基礎,直接將可執行檔案複製進映象的做法並不罕見,比如 swarm 、 coreos/etcd 。
    對於 Linux 下靜態編譯的程式來說,並不需要有作業系統提供執行時支援,所需的一切庫都已經在可執行檔案裡了,因此直接 FROM scratch 會讓映象體積更加小巧。使用 Go 語言 開發的應用很多會使用這種方式來製作映象,這也是為什麼有人認為 Go 是特別適合容器微服務架構的語言的原因之一。


  2.2 RUN:執行命令

    RUN 指令是用來執行命令列命令的。由於命令列的強大能力, RUN 指令在定製映象時是最常用的指令之一。其格式有兩種:

  • shell 格式: RUN <命令> ,就像直接在命令列中輸入的命令一樣。剛才寫的 Dockerfile 中的 RUN 指令就是這種格式。
1 RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式: RUN ["可執行檔案", "引數1", "引數2"],這更像是函式呼叫中的格式。

    Dockerfile 中每一個指令都會建立一層, RUN 也不例外。
    每一個 RUN 的行為,就和剛才我們手工建立映象的過程一樣:新建立一層,在其上執行這些命令,執行結束後, commit 這一層的修改,構成新的映象
    這是完全沒有意義的,而且很多執行時不需要的東西,都被裝進了映象裡,比如編譯環境、更新的軟體包等等。
    結果就是產生非常臃腫、非常多層的映象,不僅僅增加了構建部署的時間,也很容易出錯。

    Union FS 是有最大層數限制的,比如 AUFS,曾經是最大不得超過 42 層,現在是不得超過127 層。
    所以 Dockerfile 正確的寫法應該是這樣(例):

 1 FROM debian:jessie
 2 RUN buildDeps='gcc libc6-dev make' \
 3     && apt-get update \
 4     && apt-get install -y $buildDeps \
 5     && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
 6     && mkdir -p /usr/src/redis \
 7     && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
 8     && make -C /usr/src/redis \
 9     && make -C /usr/src/redis install \
10     && rm -rf /var/lib/apt/lists/* \
11     && rm redis.tar.gz \
12     && rm -r /usr/src/redis \
13     && apt-get purge -y --auto-remove $buildDeps

    映象是多層儲存,每一層的東西並不會在下一層被刪除,會一直跟隨著映象
    因此映象構建時,一定要確保每一層只新增真正需要新增的東西,任何無關的東西都應該清理掉

  • 映象構建上下文(Context)

    雖然表面上我們好像是在本機執行各種 docker 功能,但實際上,一切都是使用遠端呼叫形式在服務端(Docker 引擎)完成。
    當我們進行映象構建的時候,並非所有定製都會通過 RUN 指令完成,經常會需要將一些本地檔案複製進映象,比如通過 COPY 指令、 ADD 指令等。而 docker build 命令構建映象,其實並非在本地構建,而是在服務端,也就是 Docker 引擎中構建的。
    當構建的時候,使用者會指定構建映象上下文的路徑, docker build 命令得知這個路徑後,會將路徑下的所有內容打包,然後上傳給 Docker 引擎。這樣Docker 引擎收到這個上下文包後,展開就會獲得構建映象所需的一切檔案。

    一般來說,應該會將 Dockerfile 置於一個空目錄下,或者專案根目錄下。如果該目錄下沒有所需檔案,那麼應該把所需檔案複製一份過來。
    如果目錄下有些東西確實不希望構建時傳給 Docker 引擎,那麼可以用 .gitignore 一樣的語法寫一個 .dockerignore ,該檔案是用於剔除不需要作為上下文傳遞給 Docker 引擎的。
    在預設情況下,如果不額外指定 Dockerfile 的話,會將上下文目錄下的名為 Dockerfile 的檔案作為 Dockerfile。
    這只是預設行為,實際上 Dockerfile 的檔名並不要求必須為 Dockerfile ,而且並不要求必須位於上下文目錄中,比如可以用 -f ../Dockerfile.php 引數指定某個檔案作為 Dockerfile 。


  2.3 COPY:複製檔案

      格式:

  • COPY <源路徑>... <目標路徑>
  • COPY ["<源路徑1>",... "<目標路徑>"]

    和 RUN 指令一樣,也有兩種格式,一種類似於命令列,一種類似於函式呼叫。COPY 指令將從構建上下文目錄中 <源路徑> 的檔案/目錄複製到新的一層的映象內的 <目標路徑> 位置。比如:

1 COPY package.json /usr/src/app/

    <源路徑> 可以是多個,甚至可以是萬用字元,其萬用字元規則要滿足 Go 的 filepath.Match 規則,如:

1 COPY hom* /mydir/
2 COPY hom?.txt /mydir/

    <目標路徑> 可以是容器內的絕對路徑,也可以是相對於工作目錄的相對路徑(工作目錄可以用 WORKDIR 指令來指定)。目標路徑不需要事先建立,如果目錄不存在會在複製檔案前先行建立缺失目錄。
    此外,還需要注意一點,使用 COPY 指令,原始檔的各種元資料都會保留。比如讀、寫、執行許可權、檔案變更時間等。這個特性對於映象定製很有用。特別是構建相關檔案都在使用 Git 進行管理的時候。


  2.4 ADD:更高階的複製檔案

  • 設定容器啟動時第一個執行的命令及其引數。
  • 可以通過 使用命令 docker run --entrypoint 來覆蓋映象中的 ENTRYPOINT 指令的內容。
  • 將原始檔複製到映象中,原始檔要與Dockerfile 位於相同目錄中,或者是一個URL。

    有如下注意事項:

  • 如果源路徑是個檔案,且目標路徑是以 / 結尾, 則 docker 會把目標路徑當作一個目錄,會把原始檔拷貝到該目錄下。
  • 如果目標路徑不存在,則會自動建立目標路徑。
  • 如果源路徑是個檔案,且目標路徑是不是以 / 結尾,則 docker 會把目標路徑當作一個檔案。
  • 如果目標路徑不存在,會以目標路徑為名建立一個檔案,內容同源檔案。
  • 如果目標檔案是個存在的檔案,會用原始檔覆蓋它,當然只是內容覆蓋,檔名還是目標檔名。
  • 如果目標檔案實際是個存在的目錄,則會原始檔拷貝到該目錄下。注意,這種情況下,最好顯示的以 / 結尾,以避免混淆。
  • 如果源路徑是個目錄,且目標路徑不存在,則 docker 會自動以目標路徑建立一個月錄,把源路徑月錄下的檔案拷貝進來。
  • 如果目標路徑是個已經存在的目錄,則 docker 會把源路徑目錄下的檔案拷貝到該目錄下。
  • 如果原始檔是個歸檔檔案(壓縮檔案),則 docker會自動幫解壓。

    URL 下載和解壓特性不能一起使用。任何壓縮檔案通過 URL 拷貝,都不會自動解壓。

    ADD 指令和 COPY 的格式和性質基本一致。但是在 COPY 基礎上增加了一些功能。比如 <源路徑> 可以是一個 URL ,這種情況下,Docker 引擎會試圖去下載這個連結的檔案放到 <目標路徑> 去。
    下載後的檔案許可權自動設定為 600 ,如果這並不是想要的許可權,那麼還需要增加額外的一層 RUN 進行許可權調整,另外,如果下載的是個壓縮包,需要解壓縮,也一樣還需要額外的一層 RUN 指令進行解壓縮。所以不如直接使用 RUN 指令,然後使用 wget 或者 curl 工具下載,處理許可權、解壓縮、然後清理無用檔案更合理。因此,這個功能其實並不實用,而且不推薦使用。

    如果 <源路徑> 為一個 tar 壓縮檔案的話,壓縮格式為 gzip , bzip2 以及 xz 的情況下, ADD 指令將會自動解壓縮這個壓縮檔案到 <目標路徑> 去。

    但在某些情況下,如果我們真的是希望複製個壓縮檔案進去,而不解壓縮,這時就不可以使用 ADD 命令了。

    在 Docker 官方的 Dockerfile 最佳實踐文件 中要求,儘可能的使用 COPY ,因為 COPY 的語義很明確,就是複製檔案而已,而 ADD 則包含了更復雜的功能,其行為也不一定很清晰。最適合使用 ADD 的場合,就是所提及的需要自動解壓縮的場合。

    另外需要注意的是, ADD 指令會令映象構建快取失效,從而可能會令映象構建變得比較緩慢。

    因此在 COPY 和 ADD 指令中選擇的時候,可以遵循這樣的原則,所有的檔案複製均使用 COPY 指令,僅在需要自動解壓縮的場合使用 ADD 。


  2.5 CMD:容器啟動命令

    CMD 指令的格式和 RUN 相似,也是兩種格式:

  • shell 格式: CMD <命令> 引數1 引數2
  • exec 格式: CMD ["可執行檔案", "引數1", "引數2"...]
  • 引數列表格式: CMD ["引數1", "引數2"...] 。

    在指定了 ENTRYPOINT 指令後,用 CMD 指定具體的引數。
    Docker 不是虛擬機器,容器就是程序。既然是程序,那麼在啟動容器的時候,需要指定所執行的程式。
    啟動容器時預設執行的命令或者指令碼,Dockerfile只 能有一條CMD命令。如果指定多條命令,只執行最後一條命令。
    如果在 docker run 時指定了命令或者映象中有 ENTRYPOINT,那麼 cmd 就會被覆蓋。


  2.6 ENTRYPOINT:指定執行時要執行的命令

  • 格式:ENTRYPOINT [“要執行的程式”,“引數1”,“引數2”]

    設定容器啟動時第一個執行的命令及其引數。
    可以通過使用命令 docker run --entrypoint 來覆蓋映象中的 ENTRYPOINT 指令的內容。


  2.7 ENV:設定環境變數

    格式有兩種:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...

    設定一個環境變數的值,會被後面的RUN使用。

    下列指令可以支援環境變數展開:

  • ADD 、 COPY 、 ENV 、 EXPOSE 、 LABEL 、 USER 、 WORKDIR 、 VOLUME 、 STOPSIGNAL 、 ONBUILD 。

    可以從這個指令列表裡感覺到,環境變數可以使用的地方很多,很強大。通過環境變數,我們可以讓一份 Dockerfile 製作更多的映象,只需使用不同的環境變數即可。


  2.8 ARG:構建引數

  • 格式: ARG <引數名>[=<預設值>]

    構建引數和 ENV 的效果一樣,都是設定環境變數。所不同的是, ARG 所設定的構建環境的環境變數,在將來容器執行時是不會存在這些環境變數的。但是不要因此就使用 ARG 儲存密碼之類的資訊,因為 docker history 還是可以看到所有值的。

    Dockerfile 中的 ARG 指令是定義引數名稱,以及定義其預設值。該預設值可以在構建命令 docker build 中用 --build-arg <引數名>=<值> 來覆蓋。

    在 1.13 之前的版本,要求 –build-arg 中的引數名,必須在 Dockerfile 中用 ARG 定義過了,換句話說,就是 –build-arg 指定的引數,必須在 Dockerfile 中使用了。如果對應引數沒有被使用,則會報錯退出構建。從 1.13 開始,這種嚴格的限制被放開,不再報錯退出,而是顯示警告資訊,並繼續構建。


  2.9 VOLUME:定義資料卷目錄

    在容器中建立一個掛載點。
    格式為:

  • VOLUME ["<路徑1>", "<路徑2>"...]
  • VOLUME <路徑>

    容器執行時應該儘量保持容器儲存層不發生寫操作,對於資料庫類需要儲存動態資料的應用,其資料庫檔案應該保存於卷(volume)中。為了防止執行時使用者忘記將動態檔案所儲存目錄掛載為卷,在 Dockerfile 中,我們可以事先指定某些目錄掛載為匿名卷,這樣在執行時如果使用者不指定掛載,其應用也可以正常執行,不會向容器儲存層寫入大量資料。


  2.10 EXPOSE:宣告埠

    指定新映象載入到 Docker 時要開啟的埠。

  • 格式:EXPOSE <埠1> [<埠2>...]

    EXPOSE 指令是宣告執行時容器提供服務埠,這只是一個宣告,在執行時並不會因為這個宣告應用就會開啟這個埠的服務。在 Dockerfile 中寫入這樣的宣告有兩個好處,一個是幫助映象使用者理解這個映象服務的守護埠,以方便配置對映;另一個用處則是在執行時使用隨機埠對映時,也就是 docker run -P 時,會自動隨機對映 EXPOSE 的埠。


  2.11 WORKDIR:指定工作目錄

    為後續的 RUN、 CMD、 ENTRYPOINT 指定工作目錄。

  • 格式:WORKDIR <工作目錄路徑>

    使用 WORKDIR 指令可以來指定工作目錄(或者稱為當前目錄),以後各層的當前目錄就被改為指定的目錄,如該目錄不存在, WORKDIR 會幫你建立目錄。


  2.12 USER:指定當前使用者

    指定執行容器時的使用者。

  • 格式: USER <使用者名稱/UID>

    USER 指令和 WORKDIR 相似,都是改變環境狀態並影響以後的層。 WORKDIR 是改變工作目錄, USER 則是改變之後層的執行 RUN , CMD 以及 ENTRYPOINT 這類命令的身份。
    和 WORKDIR 一樣, USER 只是幫助你切換到指定使用者而已,這個使用者必須是事先建立好的,否則無法切換。


  2.13 HEALTHCHECK:健康檢查

    格式:

  • HEALTHCHECK [選項] CMD <命令> :設定檢查容器健康狀況的命令
  • HEALTHCHECK NONE :如果基礎映象有健康檢查指令,使用這行可以遮蔽掉其健康檢查指令

    HEALTHCHECK 指令是告訴 Docker 應該如何進行判斷容器的狀態是否正常。

    HEALTHCHECK 支援下列選項:

  • interval=<間隔> :兩次健康檢查的間隔,預設為 30 秒;
  • timeout=<時長> :健康檢查命令執行超時時間,如果超過這個時間,本次健康檢查就被視為失敗,預設 30 秒;
  • retries=<次數> :當連續失敗指定次數後,則將容器狀態視為 unhealthy ,預設 3 次。

    和 CMD , ENTRYPOINT 一樣, HEALTHCHECK 只可以出現一次,如果寫了多個,只有最後一個生效。
    在 HEALTHCHECK [選項] CMD 後面的命令,格式和 ENTRYPOINT 一樣,分為 shell 格式,和 exec 格式。
    命令的返回值決定了該次健康檢查的成功與否: 0 :成功; 1 :失敗; 2 :保留,不要使用這個值。


  2.14 ONBUILD 命令

    指定所生成的映象作為一個基礎映象時所要執行的命令。

    ONBUILD 是一個特殊的指令,它後面跟的是其它指令,比如 RUN , COPY 等,而這些指令,在當前映象構建時並不會被執行。
    只有當以當前映象為基礎映象,去構建下一級映象的時候才會被執行。

  • 格式: ONBUILD <其它指令>

    當在一個 Dockerfile 檔案中加上 ONBUILD 指令, 該指令對利用該 Dockerfile 構建映象(比如為 A 映象)不會產生實質性影響。
    但是當編寫一個新的 Dockerfile 檔案來基於A映象構建一個映象(比如為 B 映象)時,這時構造 A 映象的 Dockerfile 檔案中的 ONBUILD 指令就生效了,在構建 B 映象的過程中,首先會執行     ONBUILD 指令指定的指令,然後才會執行其它指令。


3. 映象構建例項
  3.1 Nginx 映象

 1 mkdir /root/nginx
 2 cd /root/nginx      #拉入軟體包(nginx-1.12.0.tar.gz)
 3 
 4 vim Dockerfile
 5 
 6 FROM centos:7
 7 MAINTAINER wt
 8 RUN yum -y update
 9 RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make
10 RUN useradd -M -s /sbin/nologin nginx
11 
12 ADD nginx-1.12.0.tar.gz /usr/local/src
13 WORKDIR /usr/local/src/nginx-1.12.0
14 RUN ./configure \
15 --prefix=/usr/local/nginx \
16 --user=nginx \
17 --group=nginx \
18 --with-http_stub_status_module && make && make install
19 
20 ENV PATH /usr/local/nginx/sbin:$PATH
21 
22 EXPOSE 80
23 EXPOSE 443
24 RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
25 
26 CMD ["/usr/local/nginx/sbin/nginx"]

    Dockerfile 檔案裡有幾個 ADD 就說明需要幾個檔案 ( Dockerfile 檔案不包含在內)

1 ##生成映象
2 
3 docker build -t nginx:nginxweb .
4 
5 
6 ##啟動容器
7 
8 docker run -d -P nginx:nginxweb

  3.2 Tomcat 映象

 1 mkdir tomcat
 2 cd tomcat/        #拉入軟體包(jdk-8u201-linux-x64.rpm   apache-tomcat-9.0.16.tar.gz)
 3 
 4 vim Dockerfile
 5 
 6 FROM centos:7
 7 MAINTAINER wt
 8 ADD jdk-8u201-linux-x64.rpm /usr/local/
 9 
10 WORKDIR /usr/local/
11 RUN rpm -ivh jdk-8u201-linux-x64.rpm
12 ENV JAVA_HOME=/usr/java/jdk1.8.0_201-amd64
13 ENV CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
14 ENV PATH=$JAVA_HOME/bin:$PATH
15 
16 ADD apache-tomcat-9.0.16.tar.gz /usr/local/
17 WORKDIR /usr/local/
18 RUN mv apache-tomcat-9.0.16 /usr/local/tomcat
19 
20 EXPOSE 8080
21 
22 CMD ["/usr/local/tomcat/bin/catalina.sh","run"]
23 #ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]
1 ##生成映象
2 
3 docker build -t tomcat:tomcatweb .
4 
5 ##啟動容器
6 
7 docker run -d --name tomcatweb -p 1234:8080 tomcat:tomcatweb

  3.3 SSHD 映象

 1 mkdir sshd
 2 cd sshd/
 3 
 4 vim Dockerfile
 5 
 6 FROM centos:7
 7 MAINTAINER wt
 8 RUN yum -y install openssh* net-tools lsof telnet passwd
 9 RUN echo "123456" | passwd --stdin root
10 RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
11 RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
12 RUN sed -i '/^session\s\+required\s\+pam_loginuid.so/s/^/#/' /etc/pam.d/sshd
13 RUN mkdir -p /root/.ssh && chown root:root /root && chmod 700 /root/.ssh
14 EXPOSE 22
15 CMD ["/usr/sbin/sshd","-D"]
1 ##生成映象
2 
3 docker build -t sshd:test .
4 
5 ##啟動容器
6 
7 docker run -d -P sshd:test
8 ssh localhost -p 埠號

  3.4 Systemctl 映象

 1 mkdir systemctl
 2 cd systemctl
 3 
 4 vim Dockerfile
 5 
 6 FROM sshd:test
 7 MAINTAINER wt
 8 ENV container docker
 9 RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *;do [ $i== \
10 systemd-tmpfiles-setup.service ] || rm -f $i;done);\
11 rm -f /lib/systemd/system/multi-user.target.wants/*;\
12 rm -f /etc/systemd/system/*.wants/*;\
13 rm -f /lib/systemd/system/local-fs.target.wants/*;\
14 rm -f /lib/systemd/system/sockets.target.wants/*udev*;\
15 rm -f /lib/systemd/system/sockets.target.wants/*initctl*;\
16 rm -f /lib/systemd/system/basic.target.wants/*;\
17 rm -f /lib/systemd/system/anaconda.target.wants/*;
18 VOLUME ["/sys/fs/cgroup"]
19 CMD ["/usr/sbin/init"]
 1 ##生成映象
 2 
 3 docker build -t systemctl:systemctl .
 4 
 5 ##啟動容器
 6 
 7 docker run --privateged -it -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd:systemctl /sbin/init & 
 8 
 9 ##登入容器進行測試
10 
11 docker exec -it systemctl /bin/bash
12 
13 systemctl status sshd
14 systemctl start sshd
15 systemctl status sshd

  3.5 MySQL 映象

 1 mkdir mysql
 2 cd mysql/
 3 
 4 vim Dockerfile
 5 
 6 FROM centos:7
 7 MAINTAINER wt
 8 EXPOSE 3306
 9 
10 ADD mysql-boost-5.7.20.tar.gz /usr/local/src
11 WORKDIR /usr/local/src/mysql-5.7.20
12 RUN useradd mysql -M -s /sbin/nologin
13 RUN yum -y install gcc \
14 gcc-c++ \
15 make \
16 ncurses \
17 ncurses-devel \
18 bison \
19 cmake
20 RUN cmake \
21 -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
22 -DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock \
23 -DSYSCONFDIR=/etc \
24 -DSYSTEMD_PID_DIR=/usr/local/mysql \
25 -DDEFAULT_CHARSET=utf8 \
26 -DDEFAULT_COLLATION=utf8_general_ci \
27 -DWITH_INNOBASE_STORAGE_ENGINE=1 \
28 -DWITH_ARCHIVE_STORAGE_ENGINE=1 \
29 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
30 -DWITH_PERFSCHEMA_STORAGE_ENGINE=1 \
31 -DMYSQL_DATADIR=/usr/local/mysql/data \
32 -DWITH_BOOST=boost \
33 -DWITH_SYSTEMD=1
34 RUN make -j 4 && make install
35 RUN chown -R mysql:mysql /usr/local/mysql/
36 RUN rm -rf /etc/my.cnf
37 WORKDIR /etc/
38 ADD my.cnf /etc/
39 
40 
41 RUN chown mysql:mysql /etc/my.cnf
42 
43 ENV PATH $PATH:/usr/local/mysql/bin:/usr/local/mysql/lib
44 RUN /usr/local/mysql/bin/mysqld \
45 --initialize-insecure \
46 --user=mysql \
47 --basedir=/usr/local/mysql \
48 --datadir=/usr/local/mysql/data
49 
50 RUN cp /usr/local/mysql/usr/lib/systemd/system/mysqld.service /lib/systemd/system/
51 RUN echo -e "#!/bin/bash \nsystemctl enable mysqld" > /run.sh
52 RUN chmod 755 /run.sh
53 RUN sh /run.sh
54 
55 CMD ["init"]
 1 ##配置檔案
 2 
 3 
 4 vim /mysql/my.cnf
 5 
 6 [client]
 7 port = 3306
 8 default-character-set=utf8
 9 socket = /usr/local/mysql/mysql.sock
10 
11 [mysql]
12 port = 3306
13 default-character-set=utf8
14 socket = /usr/local/mysql/mysql.sock
15 
16 [mysqld]
17 user = mysql
18 basedir = /usr/local/mysql
19 datadir = /usr/local/mysql/data
20 port = 3306
21 character_set_server=utf8
22 pid-file = /usr/local/mysql/mysqld.pid
23 socket = /usr/local/mysql/mysql.sock
24 server-id = 1
25 
26 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
1 ##執行指令碼
2 
3 vim run.sh
4 
5 #!/bin/bash
6 /usr/local/mysql/bin/mysqld    
7 
8 
9 docker build -t mysql:mysql00 .
 1 ##建立容器
 2 
 3 docker run -d --name mysql -P --privileged mysql:mysql00
 4 
 5 ##啟動容器
 6 
 7 docker start 容器 id
 8 
 9 ##進入容器授權
10 
11 docker exec -it 容器id /bin/bash
12 13 mysql -u root -p        #登入MySQL
14 15 grant all privileges on *.* to 'root'@'%' identified by '123456';
16 grant all privileges on *.* to 'root'@'localhost' identified by '123456';
17 18 flush privileges;
19 
20 exit
1 ##在宿主機 yum 安裝 MySQL
2 
3 yum -y install mysql
4 
5 ##客戶端連線 MySQL 容器
6 
7 mysql -uroot -p123456 -h 192.168.153.40 -P3306

-