title: DockerFile 編譯語法詳解(5)
date: 2018-12-16 16:53:20
tags:html
Docker是基於Go語言實現的開源容器項目,Docker讓開發者能夠打包他們的應用以及依賴包到一個可移植的容器中,而後發佈到任何流行的 Linux 機器上,也能夠實現虛擬化.容器是徹底使用沙箱機制,相互之間不會有任何接口,Docker誕生於2013年年初,最初發起者是dotCloud公司.Docker自開源後受到普遍的關注和討論,目前已有多個相關項目(包括Docker三劍客、Kubernetes等),逐漸造成了圍繞Docker容器的生態體系,因爲Docker在業界形成的影響力實在太大,dotCloud公司後來也直接更名爲Docker Inc,並專一於Docker相關技術和產品的開發.java
Dockerfile是一個文本格式的配置文件,用戶可使用Dockerfile來快速建立自定義的鏡像,本小結首先介紹Dockerfile典型的基本結構和它支持的衆多指令,並具體講解經過這些指令來編寫定製鏡像的Dockerfile,以及如何生成鏡像.最後介紹使用Dockerfile的一些最佳實踐經驗.
python
Dockerfile由一行行命令語句組成,而且支持以#開頭的註釋行,通常而言,Dockerfile分爲四部分.基礎鏡像信息、維護者信息、鏡像操做指令和容器啓動時執行指令.例以下面的一個小例子.linux
# This Dockerfile uses the ubuntu image FROM ubuntu:lastest # Maintainer: docker_user <docker_user at email.com> (@docker_user) MAINTAINER docker_user docker_user@email.com # Commands to update the image RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list RUN apt-get update && apt-get install -y nginx RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf # Commands when creating a new container CMD /usr/sbin/nginx
其中,一開始必須指明所基於的鏡像名稱,接下來通常是說明維護者信息.後面則是鏡像操做指令,例如RUN指令,RUN指令將對鏡像執行跟隨的命令.每運行一條RUN指令,鏡像就添加新的一層,並提交.最後是CMD指令,用來指定運行容器時的操做命令.nginx
實例1: 在debian:latest
基礎鏡像基礎上安裝Nginx環境,從而建立一個新的nginx鏡像.golang
FROM debian:latest MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com" ENV NGINX_VERSION 1.10.1-1~jessie RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC64107 9A6ABABF5BD827BD9BF62 \ && echo "deb http://nginx.org/packages/debian/ jessie nginx" >> /etc/ apt/sources.list \ && apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y \ ca-certificates \ nginx=${NGINX_VERSION} \ nginx-module-xslt \ nginx-module-geoip \ nginx-module-image-filter \ nginx-module-perl \ nginx-module-njs \ gettext-base \ && rm -rf /var/lib/apt/lists/* # forward request and error logs to docker log collector RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log EXPOSE 80 443 CMD ["nginx", "-g", "daemon off;"]
實例2: 基於buildpack-deps:latest
基礎鏡像,安裝Golang相關環境,製做一個GO語言的運行環境鏡像.redis
FROM buildpack-deps:lastest # gcc for cgo RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ gcc \ libc6-dev \ make \ && rm -rf /var/lib/apt/lists/* ENV GOLANG_VERSION 1.6.3 ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz ENV GOLANG_DOWNLOAD_SHA256 cdde5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd 7561275a87aeb RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \ && echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - \ && tar -C /usr/local -xzf golang.tar.gz \ && rm golang.tar.gz ENV GOPATH /go ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH" WORKDIR $GOPATH COPY go-wrapper /usr/local/bin/
指令的通常格式爲INSTRUCTION arguments
指令包括FROM、MAINTAINER、RUN等,參見下表.docker
指 令 | 指 令 說 明 |
---|---|
FROM | 建立鏡像的基礎鏡像 |
MAINTAINER | 維護者信息(說明) |
RUN | 運行命令,安裝軟件用 |
CMD | 啓動容器時默認執行的命令 |
LABEL | 指生成鏡像的元數據標籤信息 |
EXPOSE | 聲明鏡像內服務所監聽的端口 |
ENV | 聲明環境變量 |
ADD | 複製指令,將
|
COPY(推薦) | 複製指令,將
|
ENTRYPOINT | 指定鏡像的默認入口 |
VOLUME | 建立數據卷掛載點 |
USER | 指定運行容器時的用戶名或UID |
WORKDIR | 配置工做目錄 |
ARG | 指定鏡像內使用的參數 |
ONBUILD | 配置當所建立鏡像做爲其餘鏡像基礎時,所執行的命令 |
STOPSIGNAL | 容器退出的信號值 |
HEALTHCHECK | 如何進行健康檢查 |
SHELL | 指定使用SHELL時的默認shell類型 |
接下來,我將詳細介紹幾個經常使用命令的參數的詳細說明信息.shell
FROM:(指定基礎鏡像的名稱)apache
構建指令,必須指定且須要在Dockerfile其餘指令的前面.後續的指令都依賴於該指令指定的image,FROM指令指定的基礎image能夠是官方遠程倉庫中的,也能夠位於本地倉庫.
example: FROM centos:latest FROM ubuntu:14.04
MAINTAINER:(指定鏡像建立者信息)
構建指令,用於將image的製做者相關的信息寫入到image中,當咱們對該image執行docker inspect命令時,輸出中有相應的字段記錄該信息.
example: MAINTAINER LyShark "www.mkdirs.com"
RUN:(運行命令,安裝軟件用)
RUN指令是用來執行命令行命令的,因爲命令行的強大能力,RUN指令在定製鏡像時是最經常使用的指令之一.
設置指令,用於container啓動時指定的操做.該操做能夠是執行自定義腳本,也能夠是執行系統命令.該指令只能在文件中存在一次,若是有多個,則只執行最後一條.
FROM centos:latest RUN yum install -y gcc libc6-dev make RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" RUN mkdir -p /usr/src/redis RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 RUN make -C /usr/src/redis RUN make -C /usr/src/redis install
Dockerfile 中每個指令都會創建一層,RUN也不例外.每個RUN的行爲,就和剛纔咱們手工創建鏡像的過程同樣,新創建一層,在其上執行這些命令,執行結束後,commit 這一層的修改,構成新的鏡像.
而上面的這種寫法,建立了 6 層鏡像.這是徹底沒有意義的,不只僅增長了構建部署的時間,也很容易出錯,這是不少初學 Docker 的人常犯的一個錯誤,Union FS 是有最大層數限制的,好比 AUFS曾經是最大不得超過 42 層,如今是不得超過127 層.
上面的 Dockerfile 正確的寫法應該是這樣:
FROM centos:latest RUN buildDeps='gcc libc6-dev make' \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \ && mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && make -C /usr/src/redis \ && make -C /usr/src/redis install \ && rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps
CMD:(設置容器啓動時執行的操做)
設置指令,用於容器啓動時指定的操做,該操做能夠是執行自定義腳本,也能夠是執行系統命令,該指令只能在文件中存在一次,若是有多個,則只執行最後一條.
example: CMD echo "Hello, World!"
ENTRYPOINT:(設置容器啓動時執行的操做)
設置指令,指定容器啓動時執行的命令,能夠屢次設置,可是隻有最後一個有效.
example: ENTRYPOINT ls -l
該指令的使用分爲兩種狀況,一種是獨自使用,另外一種和CMD指令配合使用.當獨自使用時,若是你還使用了CMD命令且CMD是一個完整的可執行的命令,那麼CMD指令和ENTRYPOINT會互相覆蓋只有最後一個CMD或者ENTRYPOINT有效.以下命令:CMD指令將不會被執行,只有ENTRYPOINT指令被執行
example: CMD echo "Hello, World!" ENTRYPOINT ls -l
另外一種用法和CMD指令配合使用來指定ENTRYPOINT的默認參數,這時CMD指令不是一個完整的可執行命令,僅僅是參數部分:ENTRYPOINT指令只能使用JSON方式指定執行命令,而不能指定參數.
example: FROM centos:latest CMD ["-l"] ENTRYPOINT ["/usr/bin/ls"]
USER:(設置container容器的用戶)
設置指令,設置啓動容器的用戶,默認是root用戶.或者說以那個身份的用戶運行容器,以下所示運行memcached,並以daemon用戶運行.
example: USER daemon = ENTRYPOINT ["memcached", "-u", "daemon"]
EXPOSE:(指定容器須要映射到宿主機器的端口)
設置指令,該指令會將容器中的端口映射成宿主機器中的某個端口.當你須要訪問容器的時候,能夠不是用容器的IP地址而是使用宿主機器的IP地址和映射後的端口.要完成整個操做須要兩個步驟,首先在Dockerfile使用EXPOSE設置須要映射的容器端口,而後在運行容器的時候指定-p選項加上EXPOSE設置的端口,這樣EXPOSE設置的端口號會被隨機映射成宿主機器中的一個端口號.也能夠指定須要映射到宿主機器的那個端口,這時要確保宿主機器上的端口號沒有被使用.EXPOSE指令能夠一次設置多個端口號,相應的運行容器的時候,能夠配套的屢次使用-p選項.
example: 映射一個端口 EXPOSE 22 相應的運行容器使用的命令 docker run -p port1 image 映射多個端口 EXPOSE port1 port2 port3 相應的運行容器使用的命令 docker run -p port1 -p port2 -p port3 image 還能夠指定須要映射到宿主機器上的某個端口號 docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image
ENV:(用於設置環境變量)
構建指令,在image中設置一個環境變量.設置了後,後續的RUN命令均可以使用,container啓動後,能夠經過docker inspect查看這個環境變量,也能夠經過在docker run --env key=value
時設置或修改環境變量.假如你安裝了JAVA程序,須要設置JAVA_HOME,那麼能夠在Dockerfile中這樣寫:
example: ENV JAVA_HOME /path/to/java/dirent
ADD:(從src複製文件到容器的dest路徑)
example: ADD <src> <dest> <src> 是相對被構建的源目錄的相對路徑,能夠是文件或目錄的路徑,也能夠是一個遠程的文件url <dest> 是容器中的絕對路徑
COPY:(從src複製文件到容器的dest路徑)
example: COPY <src> <dest>
VOLUME:(指定掛載點)
設置指令,使容器中的一個目錄具備持久化存儲數據的功能,該目錄能夠被容器自己使用,也能夠共享給其餘容器使用.咱們知道容器使用的是AUFS這種文件系統不能持久化數據,當容器關閉後,全部的更改都會丟失.當容器中的應用有持久化數據的需求時能夠在Dockerfile中使用該指令.
examp: FROM base VOLUME ["/tmp/data"]
WORKDIR:(切換目錄)
設置指令,能夠屢次切換(至關於cd命令),對RUN,CMD,ENTRYPOINT生效.
example: WORKDIR /p1 WORKDIR p2 RUN vim a.txt
ONBUILD:(在子鏡像中執行)
ONBUILD指定的命令在構建鏡像時並不執行,而是在它的子鏡像中執行.
example: ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src
好了關於編譯命令還有不少,這裏就不一一列舉了,更多指令操做語法請自行百度,下面咱們來看使用DockerFile編譯構建一些好玩的東西吧,相信看完下面的小例子,你就能豐衣足食了.
Apache是一個高穩定性的、商業級別的開源Web服務器.目前Apache已是世界使用排名第一的Web服務器軟件,因爲其良好的跨平臺和安全性,Apache被普遍應用在多種平臺和操做系統上.做爲Apache軟件基金會支持的項目,它的開發者社區完善而高效.自1995年發佈至今,一直以高標準進行維護與開發.Apache名稱源自美國的西南部一個印第安人部落:阿帕奇族,它支持類UNIX和Windows系統.
1.首先咱們要解決Docker容器內不得網絡問題.修改DockerDNS,默認沒有文件自行建立便可.
[root@localhost ~]# vim /etc/default/docker docker_OPTS="--dns 8.8.8.8 --dns 114.114.114.114" [root@localhost ~]# systemctl restart docker
2.接着在當前目錄建立一個Dockerfile文件,和一個index.html文件,文件內容以下.
[root@localhost ~]# vim DockerFile FROM centos:latest MAINTAINER email@email.com RUN yum install -y -q apr apr-util httpd COPY ./index.html /var/www/html/ EXPOSE 80 ENTRYPOINT apachectl start && tail -f /var/log/httpd/access_log
3.使用docker build
命令建立centos:httpd
鏡像,注意命令最後的"."表示當前目錄.
[root@localhost ~]# docker build -t centos:httpd . Sending build context to Docker daemon 18.94kB Step 1/6 : FROM centos:latest ....省略.... Successfully built 65d0de3819df Successfully tagged centos:httpd
4.下面開始使用run
指令測試鏡像,可使用-P
參數映射須要開放的端口(22和80端口)
[root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos httpd 65d0de3819df 36 seconds ago 305MB centos latest 1e1148e4cc2c 11 days ago 202MB [root@localhost ~]# docker run -itd -p 80:80 centos:httpd
Nginx是一款功能強大的開源反向代理服務器,支持HTTP、HTTPS、SMTP、POP三、IMAP等協議.它也能夠做爲負載均衡器、HTTP緩存或Web服務器.Nginx一開始就專一於高併發和高性能的應用場景,它使用類BSD開源協議,支持Linux、BSD、Mac、Solaris、AIX等類Unix系統,同時也有Windows上的移植版本.
1.首先咱們要解決Docker容器內不得網絡問題.修改DockerDNS,默認沒有文件自行建立便可.
[root@localhost ~]# vim /etc/default/docker docker_OPTS="--dns 8.8.8.8 --dns 114.114.114.114" [root@localhost ~]# systemctl restart docker
2.接着在當前目錄建立一個Dockerfile文件,和一個index.html文件,文件內容以下.
[root@localhost ~]# vim DockerFile FROM centos:latest MAINTAINER email@email.com RUN yum install -y epel-release RUN yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel RUN rpm -i http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm RUN yum install -y nginx EXPOSE 80 ENTRYPOINT nginx && tail -f /var/log/nginx/access.log #tail必須加,不然容器瞬間終止
3.開始經過dockerfile編譯生成nginx:centos
鏡像文件.
[root@localhost ~]# docker build -t nginx:centos . Sending build context to Docker daemon 18.43kB Step 1/8 : FROM centos:latest ....省略.... Successfully built 956a361043bc Successfully tagged nginx:centos
4.查看生成的鏡像文件,並運行這個鏡像測試一下吧.
[root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx centos 956a361043bc About a minute ago 591MB centos latest 1e1148e4cc2c 11 days ago 202MB [root@localhost ~]# docker run --name nginx -p 80:80 -d nginx:centos [root@localhost ~]# curl 127.0.0.1
Tomcat是由Apache軟件基金會下屬的Jakarta項目開發的一個Servlet容器,按照Sun Microsystems提供的技術規範,實現了對Servlet和Java Server Page(JSP)的支持.同時,它提供了做爲Web服務器的一些特有功能,如Tomcat管理和控制平臺、安全域管理和Tomcat閥等.因爲Tomcat自己也內含了一個HTTP服務器,也能夠看成一個單獨的Web服務器來使用.下面介紹如何定製Tomcat鏡像.
1.首先準備好原材料,Tomcat,jdk環境.
[root@localhost ~]# ls -lh total 100M -rw-r--r-- 1 root root 92M Dec 16 23:21 jdk.tar.gz -rw-r--r-- 1 root root 7.6M Dec 16 23:21 tomcat.tar.gz
2.編寫這個構建模板文件,以下內容.
[root@localhost ~]# vim Dockerfile FROM centos:latest MAINTAINER email@email.com ADD ./tomcat.tar.gz /root ADD ./jdk.tar.gz /root ENV JAVA_HOME /root/jdk1.7.0_25 ENV PATH $JAVA_HOME/bin:$PATH EXPOSE 8080 ENTRYPOINT /root/apache-tomcat-7.0.42/bin/startup.sh && tail -F /root/apache-tomcat-7.0.42/logs/catalina.out
3.使用docker build
命令建立centos:tomcat
鏡像,注意命令最後的"."表示當前目錄.
[root@localhost ~]# docker build -t centos:tomcat . Sending build context to Docker daemon 104.3MB Step 1/8 : FROM centos:lastest ....省略.... Successfully built feac1f1c6ed4 Successfully tagged centos:tomcat [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos tomcat 65d0de3819df 36 seconds ago 405MB centos latest 1e1148e4cc2c 11 days ago 202MB
4.下面開始使用run
指令測試鏡像,可使用-P
參數映射須要開放的端口(22和80端口)
[root@localhost ~]# docker run --name tomcat -p 80:8080 -d centos:tomcat [root@localhost ~]# curl 127.0.0.1:80 [root@localhost ~]# docker save 鏡像ID > /home/xxx.tar