DockerFile 編譯語法詳解(5)


title: DockerFile 編譯語法詳解(5)
date: 2018-12-16 16:53:20
tags:html

  • Docker
    categories: Docker
    copyright: true
    ---

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由一行行命令語句組成,而且支持以#開頭的註釋行,通常而言,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/


DockerFile命令詳解

指令的通常格式爲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鏡像

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鏡像

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鏡像

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
相關文章
相關標籤/搜索