30 分鐘快速入門 Docker 教程

原文地址:梁桂釗的博客java

博客地址:http://blog.720ui.comnode

歡迎關注公衆號:「服務端思惟」。一羣同頻者,一塊兒成長,一塊兒精進,打破認知的侷限性。nginx

1、歡迎來到 Docker 世界

1. Docker 與虛擬化

在沒有 Docker 的時代,咱們會使用硬件虛擬化(虛擬機)以提供隔離。這裏,虛擬機經過在操做系統上創建了一箇中間虛擬軟件層 Hypervisor ,並利用物理機器的資源虛擬出多個虛擬硬件環境來共享宿主機的資源,其中的應用運行在虛擬機內核上。可是,虛擬機對硬件的利用率存在瓶頸,由於虛擬機很難根據當前業務量動態調整其佔用的硬件資源,所以容器化技術得以流行。其中,Docker 是一個開源的應用容器引擎,讓開發者能夠打包他們的應用以及依賴包到一個可移植的容器中,而後發佈到任何流行的 Linux 機器上。git

image.png

Docker 容器不使用硬件虛擬化,它的守護進程是宿主機上的一個進程,換句話說,應用直接運行在宿主機內核上。由於容器中運行的程序和計算機的操做系統之間沒有額外的中間層,沒有資源被冗餘軟件的運行或虛擬硬件的模擬而浪費掉。github

Docker 的優點不只如此,咱們來比較一番。web

特性 Docker 虛擬機
啓動速度 秒級 分鐘級
交付/部署 開發、測試、生產環境一致 無成熟體系
性能 近似物理機 性能損耗大
體量 極小(MB) 較大(GB)
遷移/擴展 跨平臺,可複製 較爲複雜

2. 鏡像、容器和倉庫

Docker 由鏡像(Image)、容器(Container)、倉庫(Repository) 三部分組成。docker

Docker 的鏡像能夠簡單的類比爲電腦裝系統用的系統盤,包括操做系統,以及必要的軟件。例如,一個鏡像能夠包含一個完整的 centos 操做系統環境,並安裝了 Nginx 和 Tomcat 服務器。注意的是,鏡像是隻讀的。這一點也很好理解,就像咱們刻錄的系統盤其實也是可讀的。咱們可使用 docker images 來查看本地鏡像列表。shell

Docker 的容器能夠簡單理解爲提供了系統硬件環境,它是真正跑項目程序、消耗機器資源、提供服務的東西。例如,咱們能夠暫時把容器看做一個 Linux 的電腦,它能夠直接運行。那麼,容器是基於鏡像啓動的,而且每一個容器都是相互隔離的。注意的是,容器在啓動的時候基於鏡像建立一層可寫層做爲最上層。咱們可使用 docker ps -a 查看本地運行過的容器。ubuntu

Docker 的倉庫用於存放鏡像。這一點,和 Git 很是相似。咱們能夠從中心倉庫下載鏡像,也能夠從自建倉庫下載。同時,咱們能夠把製做好的鏡像 commit 到本地,而後 push 到遠程倉庫。倉庫分爲公開倉庫和私有倉庫,最大的公開倉庫是官方倉庫 Dock Hub,國內的公開倉庫也有不少選擇,例如阿里雲等。windows

image.png

3. Docker 促使開發流程變動

筆者認爲,Docker 對開發流程的影響在於使環境標準化。例如,原來咱們存在三個環境:開發(平常)環境、測試環境、生產環境。這裏,咱們對於每一個環境都須要部署相同的軟件、腳本和運行程序,如圖所示。事實上,對於啓動腳本內容都是一致的,可是沒有統一維護,常常會出問題。此外,對於運行程序而言,若是所依賴的底層運行環境不一致,也會形成困擾和異常。

image.png

如今,咱們經過引入 Docker 以後,咱們只須要維護一個 Docker 鏡像。換句話說,多套環境,一個鏡像,實現系統級別的一次構建處處運行。此時,咱們把運行腳本標準化了,把底層軟件鏡像化了,而後對於相同的將要部署的程序實行標準化部署。所以,Docker 爲咱們提供了一個標準化的運維模式,並固化運維步驟和流程。

image.png

經過這個流程的改進,咱們更容易實現 DevOps 的目標,由於咱們的鏡像生成後能夠跑在任何系統,並快速部署。此外,使用 Docker 的很大動力是基於 Docker 實現彈性調度,以更充分地利用機器資源,節省成本。

哈哈,筆者在使用 Docker 過程當中,還發現了一些很棒的收益點,例如咱們發佈回滾的時候只須要切換 TAG 並重啓便可。還好比,咱們對環境升級,也只須要升級基礎鏡像,那麼新構建的應用鏡像,自動會引用新的版本。(歡迎補充~~~)

2、從搭建 Web 服務器開始提及

1. 環境先行,安裝 Docker

如今,咱們須要安裝如下步驟安裝 Docker。

官方下載地址:(Mac):https://download.docker.com/mac/stable/Docker.dmg 阿里雲下載地址(Mac):http://mirrors.aliyun.com/docker-toolbox/mac/docker-for-mac/ 阿里雲下載地址(Windows): http://mirrors.aliyun.com/docker-toolbox/windows/docker-for-windows/

  • 安裝指南 這裏,雙擊剛剛下載的 Doker.dmg 安裝包進行安裝。 image.png

安裝完成後啓動, Mac 頂部導航欄出現了一個圖標,經過菜單能夠進行 docker 配置和退出等操做。

image.png

官方指南:https://docs.docker.com/install/ 阿里雲指南(Linux):https://yq.aliyun.com/articles/110806?spm=5176.8351553.0.0.468b1991jdT95t

  • 設置加速服務

市面上有不少加速服務的提供商,如:DaoCloud,阿里雲等。這裏,筆者使用的是阿里雲。(注意的是,筆者操做系統是 Mac,其餘操做系列參見阿里雲操做文檔) 

image.png

右鍵點擊桌面頂欄的 docker 圖標,選擇 Preferences ,在 Daemon 標籤(Docker 17.03 以前版本爲 Advanced 標籤)下的 Registry mirrors 列表中將<br />https://xxx.mirror.aliyuncs.com 加到"registry-mirrors"的數組裏,點擊 Apply & Restart 按鈕,等待 Docker 重啓並應用配置的鏡像加速器。

image.png

阿里雲操做文檔:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors

  • 查看版本

至此,咱們已經安裝完成了。這裏,咱們來查看版本。

docker version

查看結果,以下所示。

image.png

2. 實幹派,從搭建 Web 服務器開始

咱們做爲實幹派,那麼先來搭建一個 Web 服務器吧。而後,筆者帶你慢慢理解這個過程當中,作了什麼事情。首先,咱們須要拉取 centos 鏡像。

docker run -p 80 --name web -i -t centos /bin/bash

緊接着,咱們安裝 nginx 服務器,執行如下命令:

rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

安裝完 Nginx 源後,就能夠正式安裝 Nginx 了。

yum install -y nginx

至此,咱們再輸入 whereis nginx 命令就能夠看到安裝的路徑了。最後,咱們還須要將 Nginx 跑起來。

nginx

如今,咱們執行 ctrl + P +  Q 切換到後臺。而後,經過 docker ps -a 來查看隨機分配的端口。

image.png

這裏,筆者分配的端口是 32769 ,那麼經過瀏覽器訪問 http://127.0.0.1:32769 便可。

image.png

大功告成,哈哈哈~

3. 覆盤理解全過程

如今,咱們來理解下這個流程。首先,咱們輸入 docker run -p 80 --name web -i -t centos /bin/bash 命令會運行交互式容器,其中 -i 選項告訴 Docker 容器保持標準輸入流對容器開放,即便容器沒有終端鏈接,另外一個 -t 選項告訴 Docker 爲容器分配一個虛擬終端,以便於咱們接下來安裝 Nginx 服務器。(筆者備註:Docker 還支持輸入 -d 選項告訴 Docker 在後臺運行容器的守護進程)

Docker 會爲咱們建立的每個容器自動生成一個隨機的名稱。事實上,這種方式雖然便捷,可是可讀性不好,而且對咱們後期維護的理解成本會比較大。所以,咱們經過 --name web 選項告訴 Docker 建立一個名稱是 web 的容器。此外,咱們經過 -p 80 告訴 Docker 開放 80 端口,那麼, Nginx 才能夠對外經過訪問和服務。可是,咱們的宿主機器會自動作端口映射,好比上面分配的端口是 32769 ,注意的是,若是關閉或者重啓,這個端口就變了,那麼怎麼解決固定端口的問題,筆者會在後面詳細剖析和帶你實戰。

這裏,還有一個很是重要的知識點 docker run 。Docker 經過 run 命令來啓動一個新容器。Docker 首先在本機中尋找該鏡像,若是沒有安裝,Docker 在 Docker Hub 上查找該鏡像並下載安裝到本機,最後 Docker 建立一個新的容器並啓動該程序。

image.png

可是,當第二次執行  docker run 時,由於 Docker 在本機中已經安裝該鏡像,因此 Docker 會直接建立一個新的容器並啓動該程序。

image.png

注意的是,docker run 每次使用都會建立一個新的容器,所以,咱們之後再次啓動這個容器時,只須要使用命令 docker start  便可。這裏, docker start 的做用在用從新啓動已存在的鏡像,而docker run 包含將鏡像放入容器中 docker create ,而後將容器啓動 docker start ,如圖所示。

image.png

如今,咱們能夠在上面的案例的基礎上,經過 exit 命令關閉 Docker 容器。固然,若是咱們運行的是後臺的守護進程,咱們也能夠經過 docker stop web 來中止。注意的是,docker stop 和 docker kill 略有不一樣,docker stop 發送 SIGTERM 信號,而 docker kill 發送SIGKILL 信號。而後,咱們使用 docker start 重啓它。

docker start web

Docker 容器重啓後會沿用 docker run 命令指定的參數來運行,可是,此時它仍是後臺運行的。咱們必須經過 docker attach 命令切換到運行交互式容器。

docker attach web

4. 不止如此,還有更多命令

Docker 提供了很是豐富的命令。所謂一圖勝千言,咱們能夠從下面的圖片瞭解到不少信息和它們以前的用途。(能夠直接跳過閱讀,建議收藏,便於擴展閱讀)

image.png

若是但願獲取更多信息,能夠閱讀官方使用文檔。

Command Description
docker attach Attach local standard input, output, and error streams to a running container
docker build Build an image from a Dockerfile
docker builder Manage builds
docker checkpoint Manage checkpoints
docker commit Create a new image from a container’s changes
docker config Manage Docker configs
docker container Manage containers
docker cp Copy files/folders between a container and the local filesystem
docker create Create a new container
docker deploy Deploy a new stack or update an existing stack
docker diff Inspect changes to files or directories on a container’s filesystem
docker engine Manage the docker engine
docker events Get real time events from the server
docker exec Run a command in a running container
docker export Export a container’s filesystem as a tar archive
docker history Show the history of an image
docker image Manage images
docker images List images
docker import Import the contents from a tarball to create a filesystem image
docker info Display system-wide information
docker inspect Return low-level information on Docker objects
docker kill Kill one or more running containers
docker load Load an image from a tar archive or STDIN
docker login Log in to a Docker registry
docker logout Log out from a Docker registry
docker logs Fetch the logs of a container
docker manifest Manage Docker image manifests and manifest lists
docker network Manage networks
docker node Manage Swarm nodes
docker pause Pause all processes within one or more containers
docker plugin Manage plugins
docker port List port mappings or a specific mapping for the container
docker ps List containers
docker pull Pull an image or a repository from a registry
docker push Push an image or a repository to a registry
docker rename Rename a container
docker restart Restart one or more containers
docker rm Remove one or more containers
docker rmi Remove one or more images
docker run Run a command in a new container
docker save Save one or more images to a tar archive (streamed to STDOUT by default)
docker search Search the Docker Hub for images
docker secret Manage Docker secrets
docker service Manage services
docker stack Manage Docker stacks
docker start Start one or more stopped containers
docker stats Display a live stream of container(s) resource usage statistics
docker stop Stop one or more running containers
docker swarm Manage Swarm
docker system Manage Docker
docker tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
docker top Display the running processes of a container
docker trust Manage trust on Docker images
docker unpause Unpause all processes within one or more containers
docker update Update configuration of one or more containers
docker version Show the Docker version information
docker volume Manage volumes
docker wait Block until one or more containers stop, then print their exit codes

官方閱讀連接:https://docs.docker.com/engine/reference/commandline/docker/

5. 進階:倉庫與軟件安裝的簡化

還記得筆者在文章開頭介紹的「鏡像、容器和倉庫」嗎?Docker 的倉庫用於存放鏡像。咱們能夠從中心倉庫下載鏡像,也能夠從自建倉庫下載。同時,咱們能夠把製做好的鏡像從本地推送到遠程倉庫。

首先,筆者先引入一個知識點:Docker 的鏡像就是它的文件系統,一個鏡像能夠放在另一個鏡像的上層,那麼位於下層的就是它的父鏡像。因此,Docker 會存在不少鏡像層,每一個鏡像層都是隻讀的,而且不會改變。當咱們建立一個新的容器時,Docker 會構建出一個鏡像棧,並在棧的最頂層添加一個讀寫層,如圖所示。

image.png

如今,咱們能夠經過 docker images 命令查看本地的鏡像。

docker images

查詢結果,如圖所示。

image.png

這裏,對幾個名詞解釋一下含義。

  • REPOSITORY:倉庫名稱。
  • TAG: 鏡像標籤,其中 lastest 表示最新版本。注意的是,一個鏡像能夠有多個標籤,那麼咱們就能夠經過標籤來管理有用的版本和功能標籤。
  • IMAGE ID :鏡像惟一ID。
  • CREATED :建立時間。
  • SIZE :鏡像大小。

那麼,若是第一次咱們經過 docker pull centos:latest 拉取鏡像,那麼當咱們執行 docker run -p 80 --name web -i -t centos /bin/bash 時,它就不會再去遠程獲取了,由於本機中已經安裝該鏡像,因此 Docker 會直接建立一個新的容器並啓動該程序。

事實上,官方已經提供了安裝好 Nginx 的鏡像,咱們能夠直接使用。如今,咱們經過拉取鏡像的方式從新構建一個 Web 服務器。首先,咱們經過 docker search 來查找鏡像。咱們獲取到 Nginx 的鏡像清單。

docker search nginx

補充一下,咱們也能夠經過訪問 Docker Hub (https://hub.docker.com/)搜索倉庫,那麼 star 數越多,說明它越靠譜,能夠放心使用。

image.png

如今,咱們經過 docker pull nginx 拉取最新的 Nginx 的鏡像。固然,咱們也能夠經過 docker pull nginx:latest  來操做。

docker pull nginx

而後,咱們建立並運行一個容器。與前面不一樣的是,咱們經過 -d 選項告訴 Docker 在後臺運行容器的守護進程。而且,經過 8080:80 告訴 Docker 8080 端口是對外開放的端口,80 端口對外開放的端口映射到容器裏的端口號。

docker run -p 8080:80 -d --name nginx nginx

咱們再經過 docker ps -a 來查看,發現容器已經後臺運行了,而且後臺執行了 nginx 命令,並對外開放 8080 端口。

image.png

所以,經過瀏覽器訪問 http://127.0.0.1:8080 便可。

image.png

6. 其餘選擇,使用替代註冊服務器

Docker Hub 不是軟件的惟一來源,咱們也能夠切換到國內的其餘替代註冊服務器,例如阿里雲。咱們能夠登陸 https://cr.console.aliyun.com 搜索,並拉取公開的鏡像。

image.png

image.png

如今,咱們輸入 docker pull 命令進行拉取。

docker pull registry.cn-hangzhou.aliyuncs.com/qp_oraclejava/orackejava:8u172_DCEVM_HOTSWAPAGEN_JCE

這裏,筆者繼續補充一個知識點:註冊服務器的地址。事實上,註冊服務器的地址是有一套規範的。完整格式是:[倉庫主機/][用戶名/]容器短名[:標籤]。這裏,倉庫主機是 registry.cn-hangzhou.aliyuncs.com,用戶名是 qp_oraclejava,容器短名是 orackejava,標籤名是 8u172_DCEVM_HOTSWAPAGEN_JCE。事實上,咱們上面經過 docker pull centos:latest 拉取鏡像,至關於 docker pull registry.hub.docker.com/centos:latest 。

3、構建個人鏡像

經過上面的學習,筆者相信你已經對 Docker 使用有了一個大體的瞭解,就比如咱們經過 VMware 安裝了一個系統,並讓它跑了起來,那麼咱們就能夠在這個 Linux 系統(CentOS 或者 Ubuntu ) 上面工做咱們想要的任何事情。事實上,咱們還會常常把咱們安裝好的 VMware 系統進行快照備份並實現克隆來知足咱們下次快速的複製。這裏,Docker 也能夠構建定製內容的 Docker 鏡像,例如上面咱們使用官方提供的安裝好 Nginx 的 Docker 鏡像。注意的是,咱們經過基於已有的基礎鏡像,在上面添加鏡像層的方式構建新鏡像而已。

總結一下,Docker 提供自定義鏡像的能力,它可讓咱們保存對基礎鏡像的修改,並再次使用。那麼,咱們就能夠把操做系統、運行環境、腳本和程序打包在一塊兒,並在宿主機上對外提供服務。

Docker 構建鏡像有兩種方式,一種方式是使用 docker commit 命令,另一種方式使用 docker build 命令和 Dockerfile 文件。其中,不推薦使用 docker commit 命令進行構建,由於它沒有使得整個流程標準化,所以,在企業的中更加推薦使用 docker build 命令和 Dockerfile 文件來構建咱們的鏡像。咱們使用Dockerfile 文件可讓構建鏡像更具有可重複性,同時保證啓動腳本和運行程序的標準化。

1. 構建第一個 Dockerfile 文件

如今,咱們繼續實戰。這裏,咱們把一開始搭建的 Web 服務器構建一個鏡像。首先,咱們須要建立一個空的 Dokcerfile 文件。

mkdir dockerfile_test
cd dockerfile_test/
touch Dockerfile
nano Dockerfile

緊接着,咱們須要編寫一個 Dockerfile 文件,代碼清單以下

FROM centos:7
MAINTAINER LiangGzone "lianggzone@163.com"
RUN rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
RUN yum install -y nginx
EXPOSE 80

最後,咱們經過 docker build 命令進行構建。

docker build -t="lianggzone/nginx_demo:v1" .

如今, 咱們來經過 docker images 看下咱們的新鏡像吧。

image.png

2. 理解 Dockerfile 全過程

哇,咱們經過編寫一個 Dockerfile 文件順利構建了一個新的鏡像。這個過程簡單得讓人沒法相信。如今,讓咱們來理解一下這個全過程吧。首先, FROM centos:7 是 Dockerfile 必需要的第一步,它會從一個已經存在的鏡像運行一個容器,換句話說,Docker 須要依賴於一個基礎鏡像進行構建。這裏,咱們指定 centos 做爲基礎鏡像,它的版本是 7 (CentOS 7)。而後,咱們經過 MAINTAINER LiangGzone "lianggzone@163.com" 指定該鏡像的做者是 LiangGzone,郵箱是 lianggzone@163.com。這有助於告訴使用者它的做者和聯繫方式。接着,咱們執行兩個 RUN 指令進行 Nginx 的下載安裝,最後經過  EXPOSE 80 暴露 Dokcer 容器的 80 端口。注意的是,Docker 的執行順序是從上而下執行的,因此咱們要明確整個流程的執行順序。除此以外,Docker 在執行每一個指令以後都會建立一個新的鏡像層而且進行提交。

咱們使用  docker build 命令進行構建,指定 - t 告訴 Docker 鏡像的名稱和版本。注意的是,若是沒有指定任何標籤,Docker 將會自動爲鏡像設置一個 lastest 標籤。還有一點,咱們最後還有一個 . 是爲了讓 Docker 到當前本地目錄去尋找 Dockerfile 文件。注意的是,Docker 會在每一步構建都會將結果提交爲鏡像,而後將以前的鏡像層看做緩存,所以咱們從新構建相似的鏡像層時會直接複用以前的鏡像。若是咱們須要跳過,可使用 --no-cache 選項告訴 Docker 不進行緩存。

3. Dockerfile 指令詳解

Dockerfile 提供了很是多的指令。筆者這裏特別整理了一份清單,建議收藏查看。

image.png

官方地址:https://docs.docker.com/engine/reference/builder/#usage

指令辨別一:RUN、CMD、ENTRYPOINT

RUN 、 CMD 、 ENTRYPOINT  三個指令的用途很是相識,不一樣在於,RUN 指令是在容器被構建時運行的命令,而CMD 、 ENTRYPOINT 是啓動容器時執行 shell 命令,而 RUN 會被 docker run 命令覆蓋,可是  ENTRYPOINT 不會被覆蓋。事實上,docker run 命令指定的任何參數都會被看成參數再次傳遞給 ENTRYPOINT  指令。CMD 、 ENTRYPOINT 兩個指令之間也能夠一塊兒使用。例如,咱們 可使用 ENTRYPOINT 的 exec 形式設置固定的默認命令和參數,而後使用任一形式的 CMD 來設置可能更改的其餘默認值。

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

指令辨別二:ADD、COPY

ADD 、 COPY 指令用法同樣,惟一不一樣的是 ADD  支持將歸檔文件(tar, gzip, bzip2, etc)作提取和解壓操做。注意的是,COPY 指令須要複製的目錄必定要放在 Dockerfile 文件的同級目錄下。

4. 將鏡像推送到遠程倉庫

遠程倉庫:Docker Hub 

鏡像構建完畢以後,咱們能夠將它上傳到 Docker Hub 上面。首先,咱們須要經過 docker login 保證咱們已經登陸了。緊接着,咱們使用 docker push 命令進行推送。

docker push lianggzone/nginx_demo:v1

這裏,咱們瞭解下它的使用,格式是 docker push [OPTIONS] NAME[:TAG] ,其中,筆者設置 NAME 是 lianggzone/nginx_demo,TAG 是 v1。 (筆者注:推送 Docker Hub 速度很慢,耐心等待) 最後,上傳完成後訪問:https://hub.docker.com/u/lianggzone/,如圖所示。

image.png

遠程倉庫:阿里雲

同時,咱們也可使用國內的倉庫,好比阿里雲。首先,在終端中輸入訪問憑證,登陸 Registry 實例。若是你不知道是哪一個,能夠訪問 https://cr.console.aliyun.com/cn-hangzhou/instances/credentials

docker login --username=賬號 registry.cn-hangzhou.aliyuncs.com

如今,將鏡像推送到阿里雲鏡像倉庫。其中, docker tag [IMAGE_ID] registry.cn-hangzhou.aliyuncs.com/[命名空間]/[鏡像名稱]:[版本] 和 docker push registry.cn-hangzhou.aliyuncs.com/[命名空間]/[鏡像名稱]:[版本] 命令的使用以下所示。

docker tag 794c07361565 registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1
docker push registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1

最後,上傳完成後訪問:https://cr.console.aliyun.com/cn-hangzhou/instances/repositories,如圖所示。

image.png

5. Dockerfile 的 Github 源碼地址

這裏,附上我整理的 Dockerfile 的倉庫。後面,筆者會陸續更新用到的一些經常使用文件,歡迎 star 關注。

https://github.com/lianggzone/dockerfile-images

附:參考資料

(完,轉載請註明做者及出處。)

寫在末尾

【服務端思惟】:咱們一塊兒聊聊服務端核心技術,探討一線互聯網的項目架構與實戰經驗。同時,擁有衆多技術大牛的「後端圈」你們庭,期待你的加入,一羣同頻者,一塊兒成長,一塊兒精進,打破認知的侷限性。

更多精彩文章,盡在「服務端思惟」!

相關文章
相關標籤/搜索