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

Docker 是個劃時代的開源項目,它完全釋放了計算虛擬化的威力,極大提升了應用的運行效率,下降了雲計算資源供應的成本!使用 Docker,可讓應用的部署、測試和分發都變得史無前例的高效和輕鬆!php

不管是應用開發者、運維人員、仍是其餘信息技術從業人員,都有必要認識和掌握 Docker,節約有限的時間。html

系統要求

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

  • 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 CEpython

卸載舊版本

老版本的Docker被稱爲dockerdocker-engine。若是安裝了這些,請將其卸載:mysql

$ apt-get remove docker docker-engine docker.io

使用存儲庫進行安裝

首次在新的主機上安裝Docker CE以前,須要設置Docker存儲庫。以後,您能夠從存儲庫安裝和更新Dockerlinux

  • 設置存儲庫

1.更新apt軟件包索引:nginx

$ apt-get update

2.安裝軟件包以容許apt經過HTTPS使用存儲庫:git

$ apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

3.添加Docker的官方GPG密鑰:github

鑑於國內網絡問題,強烈建議使用國內源,官方源請在註釋中查看。golang

$ 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 — 從入門到實踐

https://www.gitbook.com/download/pdf/book/yeasy/docker_practice

參考:Docker 官網 Get Docker CE for Ubuntu

https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#install-using-the-convenience-script

Contact

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

關注公衆號-搜雲庫

相關文章
相關標籤/搜索