Ubuntu 17.04 x64 安裝 Docker CE 初窺 Dockerfile 部署 Nginx

搜雲庫技術團隊發表於2019-03-04

Docker 是個劃時代的開源專案,它徹底釋放了計算虛擬化的威力,極大提高了應用的執行效率,降低了雲端計算資源供應的成本!使用 Docker,可以讓應用的部署、測試和分發都變得前所未有的高效和輕鬆!

無論是應用開發者、運維人員、還是其他資訊科技從業人員,都有必要認識和掌握 Docker,節約有限的時間。

系統要求

要安裝Docker CE,您需要這些Ubuntu版本的64位版本:

  • Artful 17.10(Docker CE 17.11 Edge及更高版本)
  • ZESTY 17.04
  • Xenial 16.04(LTS)
  • Trusty 14.04(LTS)

Ubuntu x86_64,Linux armhf,s390x(IBM Z)和ppc64le(IBM Power)架構上支援Docker CE

解除安裝舊版本

老版本的Docker被稱為dockerdocker-engine。如果安裝了這些,請將其解除安裝:

$ apt-get remove docker docker-engine docker.io
複製程式碼

使用儲存庫進行安裝

首次在新的主機上安裝Docker CE之前,需要設定Docker儲存庫。之後,您可以從儲存庫安裝和更新Docker

  • 設定儲存庫

1.更新apt軟體包索引:

$ apt-get update
複製程式碼

2.安裝軟體包以允許apt通過HTTPS使用儲存庫:

$ apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common
複製程式碼

3.新增Docker的官方GPG金鑰:

鑑於國內網路問題,強烈建議使用國內源,官方源請在註釋中檢視。

$ curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

# 官方源
# $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
複製程式碼

4.新增 Docker 軟體源

鑑於國內網路問題,強烈建議使用國內源,官方源請在註釋中檢視。

然後,我們需要向 source.list 中新增 Docker 軟體源

$ sudo add-apt-repository \
    "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
    $(lsb_release -cs) \
    stable"
	

# 官方源
# $ sudo add-apt-repository \
#    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
#    $(lsb_release -cs) \
#    stable"
複製程式碼

以上命令會新增穩定版本的 Docker CE APT 映象源,如果需要最新或者測試版本的 Docker CE 請將 stable 改為 edge 或者 test。從 Docker 17.06 開始,edge test 版本的 APT 映象源也會包含穩定版本的 Docker

安裝Docker CE

1.更新apt軟體包索引。

$ apt-get update
複製程式碼

2.安裝最新版本的Docker CE,或者轉到下一步安裝特定版本。任何現有的Docker安裝都將被替換。

$ apt-get install docker-ce
複製程式碼

3.在生產系統上,您應該安裝特定版本的Docker CE,而不是始終使用最新版本。此輸出被截斷。列出可用的版本。

$ apt-cache madison docker-ce

docker-ce | 17.12.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.09.1~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.09.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.06.2~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.06.1~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
docker-ce | 17.06.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu zesty/stable amd64 Packages
複製程式碼

列表的內容取決於啟用了哪個儲存庫。選擇一個特定的版本進行安裝。第二列是版本字串。第三列是儲存庫名稱,它指出了軟體包來自哪個儲存庫,並通過擴充套件其穩定性級別。要安裝特定版本,請將版本字串附加到包名稱,並用等號(=)將它們分開:

$ sudo apt-get install docker-ce=<VERSION>
複製程式碼

4.通過執行hello-world 映像驗證是否正確安裝了Docker CE

$ docker run hello-world
複製程式碼

這個命令下載一個測試影象並在容器中執行。容器執行時,會列印一條資訊訊息並退出。

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete 
Digest: sha256:445b2fe9afea8b4aa0b2f27fe49dd6ad130dfe7a8fd0832be5de99625dad47cd
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

複製程式碼

以非root使用者身份管理Docker

預設情況下,docker 命令會使用 Unix socketDocker 引擎通訊。而只有 root 使用者和 docker 組的使用者才可以訪問 Docker 引擎的 Unix socket。出於安全考慮,一般 Linux 系統上不會直接使用 root 使用者。因此,更好地做法是將需要使用 docker 的使用者加入 docker 使用者組。

要建立docker組並新增您的使用者:

1.建立docker組。

$ sudo groupadd docker
複製程式碼

2.將您的使用者新增到docker組中。

$ sudo usermod -aG docker $USER
複製程式碼

3.登出並重新登入,如果在虛擬機器上進行測試,則可能需要重新啟動虛擬機器才能使更改生效。

4.驗證您可以不執行docker命令sudo

$ docker run hello-world
複製程式碼

解除安裝Docker CE

1.解除安裝Docker CE軟體包:

$ sudo apt-get purge docker-ce
複製程式碼

2.主機上的影象,容器,卷或自定義配置檔案不會自動刪除。刪除所有影象,容器和卷:

$ sudo rm -rf /var/lib/docker
複製程式碼

利用 commit 理解映象構成

這條命令會用nginx 映象啟動一個容器,命名為 myweb,並且對映了 80 埠,這樣我們可以用瀏覽器去訪問這個 nginx 伺服器。

$ docker run --name myweb -d -p 80:80 nginx
複製程式碼

直接訪問:http://localhost;如果使用的是 Docker Toolbox,或者是在虛擬機器、雲伺服器上安裝的 Docker,則需要將 localhost 換為虛擬機器地址或者實際雲伺服器地址。

Welcome to nginx!

現在,假設我們非常不喜歡這個歡迎頁面,我們希望改成歡迎 Docker 的文字,我們可以使用 docker exec 命令進入容器,修改其內容。

$ docker exec -it myweb bash
root@5ceb0c8274ca:/# echo '<h1>Welcome to Docker!</h1>' > /usr/share/nginx/html/index.html
root@5ceb0c8274ca:/# exit
exit
複製程式碼

直接訪問:http://localhost

Welcome to Docker!

我們修改了容器的檔案,也就是改動了容器的儲存層。我們可以通過 docker diff 命令看到具體的改動。COMMENT列有備註!

$  docker diff myweb
C /root
A /root/.bash_history
C /run
A /run/nginx.pid
C /usr/share/nginx/html/index.html
C /var/cache/nginx
D /var/cache/nginx/client_temp
D /var/cache/nginx/fastcgi_temp
D /var/cache/nginx/proxy_temp
D /var/cache/nginx/scgi_temp
D /var/cache/nginx/uwsgi_temp
root@souyunku:~/mydocker#
複製程式碼

我們可以用下面的命令將容器儲存為映象:

$ docker commit \
    --author "penglei <admin@souyunku.com>" \
    --message "修改了預設網頁" \
    myweb \
    nginx:v2
	
sha256:33b2e2aefccbaba54021c85ef7966c7d488abaa0677728e1b057c56a7734a4f0
複製程式碼

其中 --author 是指定修改的作者,而 --message 則是記錄本次修改的內容。這點和 git 版本控制相似,不過這裡這些資訊可以省略留空。

我們可以在 docker image ls 中看到這個新定製的映象:

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
nginx               v2                  33b2e2aefccb        About a minute ago   108MB
nginx               latest              3f8a4339aadd        3 days ago           108MB
hello-world         latest              f2a91732366c        5 weeks ago          1.85kB
複製程式碼
$ docker history nginx:v2
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
33b2e2aefccb        2 minutes ago       nginx -g daemon off;                            325B                修改了預設網頁
3f8a4339aadd        3 days ago          /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B                  
<missing>           3 days ago          /bin/sh -c #(nop)  STOPSIGNAL [SIGTERM]         0B                  
<missing>           3 days ago          /bin/sh -c #(nop)  EXPOSE 80/tcp                0B                  
<missing>           3 days ago          /bin/sh -c ln -sf /dev/stdout /var/log/nginx…   22B                 
<missing>           3 days ago          /bin/sh -c set -x  && apt-get update  && apt…   53.2MB              
<missing>           3 days ago          /bin/sh -c #(nop)  ENV NJS_VERSION=1.13.8.0.…   0B                  
<missing>           3 days ago          /bin/sh -c #(nop)  ENV NGINX_VERSION=1.13.8-…   0B                  
<missing>           2 weeks ago         /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B                  
<missing>           2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B                  
<missing>           2 weeks ago         /bin/sh -c #(nop) ADD file:f30a8b5b7cdc9ba33…   55.3MB 
複製程式碼

新的映象定製好後,我們可以來執行這個映象。

$ docker run --name web2 -d -p 81:80 nginx:v2
ed8c54aeb3c540981b892c0cdfbf9330114ecc935149190e073f49295f2ae147
複製程式碼

直接訪問:http://localhost:81;如果使用的是 Docker Toolbox,或者是在虛擬機器、雲伺服器上安裝的 Docker,則需要將 localhost 換為虛擬機器地址或者實際雲伺服器地址。

Welcome to Docker!

使用 Dockerfile 定製映象

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

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

還以之前定製 nginx 映象為例,這次我們使用 Dockerfile 來定製。

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

$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile
複製程式碼

其內容為:

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
複製程式碼

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

FROM 指定基礎映象

所謂定製映象,那一定是以一個映象為基礎,在其上進行定製。就像我們之前執行了一個 nginx 映象的容器,再進行修改一樣,基礎映象是必須指定的。而 FROM 就是指定基礎映象,因此一個 DockerfileFROM 是必備的指令,並且必須是第一條指令。

Docker Store 上有非常多的高質量的官方映象,有可以直接拿來使用的服務類的映象,如 nginxredismongomysqlhttpdphptomcat 等;也有一些方便開發、構建、執行各種語言應用的映象,如 nodeopenjdkpythonrubygolang 等。可以在其中尋找一個最符合我們最終目標的映象為基礎映象進行定製。

如果沒有找到對應服務的映象,官方映象中還提供了一些更為基礎的作業系統映象,如 ubuntudebiancentosfedoraalpine 等,這些作業系統的軟體庫為我們提供了更廣闊的擴充套件空間。

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

FROM scratch
...
複製程式碼

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

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

RUN 執行命令

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

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

既然 RUN 就像 Shell 指令碼一樣可以執行命令,那麼我們是否就可以像 Shell 指令碼一樣把每個命令對應一個 RUN 呢?比如這樣:

FROM debian:jessie

RUN apt-get update
RUN apt-get 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 這一層的修改,構成新的映象。

而上面的這種寫法,建立了 7 層映象。這是完全沒有意義的,而且很多執行時不需要的東西,都被裝進了映象裡,比如編譯環境、更新的軟體包等等。結果就是產生非常臃腫、非常多層的映象,不僅僅增加了構建部署的時間,也很容易出錯。 這是很多初學 Docker 的人常犯的一個錯誤。

Union FS 是有最大層數限制的,比如 AUFS,曾經是最大不得超過 42 層,現在是不得超過 127 層。

上面的 Dockerfile 正確的寫法應該是這樣:

FROM debian:jessie

RUN buildDeps='gcc libc6-dev make' \
    && apt-get update \
    && 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
複製程式碼

首先,之前所有的命令只有一個目的,就是編譯、安裝 redis 可執行檔案。因此沒有必要建立很多層,這只是一層的事情。因此,這裡沒有使用很多個 RUN 對一一對應不同的命令,而是僅僅使用一個 RUN 指令,並使用 && 將各個所需命令串聯起來。將之前的 7 層,簡化為了 1 層。在撰寫 Dockerfile 的時候,要經常提醒自己,這並不是在寫 Shell 指令碼,而是在定義每一層該如何構建。

並且,這裡為了格式化還進行了換行。Dockerfile 支援 Shell 類的行尾新增 \ 的命令換行方式,以及行首 # 進行註釋的格式。良好的格式,比如換行、縮排、註釋等,會讓維護、排障更為容易,這是一個比較好的習慣。

此外,還可以看到這一組命令的最後新增了清理工作的命令,刪除了為了編譯構建所需要的軟體,清理了所有下載、展開的檔案,並且還清理了 apt 快取檔案。這是很重要的一步,我們之前說過,映象是多層儲存,每一層的東西並不會在下一層被刪除,會一直跟隨著映象。因此映象構建時,一定要確保每一層只新增真正需要新增的東西,任何無關的東西都應該清理掉。

很多人初學 Docker 製作出了很臃腫的映象的原因之一,就是忘記了每一層構建的最後一定要清理掉無關檔案。

構建映象

好了,讓我們再回到之前定製的 nginx 映象的 Dockerfile 來。現在我們明白了這個 Dockerfile 的內容,那麼讓我們來構建這個映象吧。

Dockerfile 檔案所在目錄執行:


$ docker build -t nginx:v3 .

Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM nginx
 ---> 3f8a4339aadd
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 5cdac6d29a52
Removing intermediate container 5cdac6d29a52
 ---> 56a1b67b2533
Successfully built 56a1b67b2533
Successfully tagged nginx:v3
複製程式碼

從命令的輸出結果中,我們可以清晰的看到映象的構建過程。在 Step 2 中,如同我們之前所說的那樣,RUN 指令啟動了一個容器 5cdac6d29a52,執行了所要求的命令,並最後提交了這一層 56a1b67b2533,隨後刪除了所用到的這個容器 5cdac6d29a52

這裡我們使用了 docker build 命令進行映象構建。其格式為:

$ docker build [選項] <上下文路徑/URL/->
複製程式碼

**映象構建上下文(Context)**如果注意,會看到 docker build 命令最後有一個 .. 表示當前目錄

其它 docker build 的用法

直接用 Git repo 進行構建

或許你已經注意到了,docker build 還支援從 URL 構建,比如可以直接從 Git repo 中構建:

感謝:漠然提供 Git dockerfile repo

$ docker build https://github.com/mritd/dockerfile.git#:alpine-glibc
複製程式碼
...

Executing ca-certificates-20171114-r0.post-deinstall
Executing busybox-1.27.2-r6.trigger
OK: 11 MiB in 14 packages
Removing intermediate container baf41e622959
 ---> aded3329be1b
Step 3/3 : ENV LANG=C.UTF-8
 ---> Running in 8c34e0f4d25b
Removing intermediate container 8c34e0f4d25b
 ---> c493a5aa5eb7
Successfully built c493a5aa5eb7
複製程式碼

這行命令指定了構建所需的 Git repo,並且指定預設的 master 分支,構建目錄為 /alpine-glibc/,然後 Docker 就會自己去 git clone 這個專案、切換到指定分支、並進入到指定目錄後開始構建。

用給定的 tar 壓縮包構建

$ docker build http://server/context.tar.gz
複製程式碼

如果所給出的 URL 不是個 Git repo,而是個 tar 壓縮包,那麼 Docker 引擎會下載這個包,並自動解壓縮,以其作為上下文,開始構建。

從標準輸入中讀取 Dockerfile 進行構建

$ docker build - < Dockerfile
複製程式碼

$ cat Dockerfile | docker build -
複製程式碼

如果標準輸入傳入的是文字檔案,則將其視為 Dockerfile,並開始構建。這種形式由於直接從標準輸入中讀取 Dockerfile 的內容,它沒有上下文,因此不可以像其他方法那樣可以將本地檔案 COPY 進映象之類的事情。

從標準輸入中讀取上下文壓縮包進行構建

$ docker build - < context.tar.gz
複製程式碼

如果發現標準輸入的檔案格式是 gzip、bzip2 以及xz 的話,將會使其為上下文壓縮包,直接將其展開,將裡面視為上下文,並開始構建。

參考:Docker — 從入門到實踐

www.gitbook.com/download/pd…

參考:Docker 官網 Get Docker CE for Ubuntu

docs.docker.com/engine/inst…

Contact

  • 作者:鵬磊
  • 出處:www.ymq.io
  • Email:admin@souyunku.com
  • 版權歸作者所有,轉載請註明出處
  • Wechat:關注公眾號,搜雲庫,專注於開發技術的研究與知識分享

關注公眾號-搜雲庫
搜雲庫

相關文章