如下記錄 Docker 中的經常使用操做、指令,使得你們可以快速地使用 Docker。php
爲何要使用 Docker?就我的而言,Docker 能提供的最大便利在於這種技術面對程序環境遷移時所表現的卓越性。html
這種性能使得咱們沒必要在分享代碼或項目合做、交接時附帶一長串的環境配置指南進行版本限制和擴展描述;也沒必要再特地記錄本身對現有環境的配置改變,以避免下次系統遷移時手足無措;更爲重要的是,Docker 在提供以上解決方案的同時沒有把解法變得複雜,相反的,它提供了一種更快、更容易的方式。nginx
Docker 獨到的對增量和文件層的應用,使得鏡像下載、共享 & 隔離、版本控制等問題的解決方法變得格外優雅。有興趣的讀者能夠參考「按部就班學 Docker」這本書。c++
訪問下面的網址,從菜單的 Get Docker
中選擇適合的版本進行下載。web
https://www.docker.com/
Mac 和 Windows 中均可以使用桌面版傻瓜式安裝。docker
在 Centos 中,安裝步驟分爲 安裝 Docker 與 安裝 Docker Compose。注意,Docker 的安裝受限於系統內核版本,可查看 參考連接。shell
安裝完成後,能夠經過如下方式查看 Docker 版本:json
docker --version
國內訪問官方鏡像的速度較慢,能夠選用國內的鏡像源,這裏給出 DaoCloud 和阿里雲的鏡像源,鏡像源更換方法在如下網址中都有說明:ubuntu
DaoCloud: https://www.daocloud.io/mirror AliCloud: https://cr.console.aliyun.com/#/accelerator
能夠從如下網址中搜索須要的鏡像:segmentfault
// 官方: https://store.docker.com/ // DaoCloud: http://hub.daocloud.io/ // AliCloud https://dev.aliyun.com/
鏡像:從鏡像市場中下載的即爲鏡像,能夠理解爲容器的模板。
容器:應用程序運行的環境,容器的建立依賴於某一鏡像。注意,容器不是鏡像的拷貝,容器只是在鏡像之上創建了一層讀寫層,用以覆蓋容器內對鏡像配置、文件的修改。採用這一方式能夠避免因頻繁的鏡像複製而致使的資源浪費。具體能夠參考相關書籍或博客。
能夠在安裝了 Docker 的機器上使用如下指令搜索鏡像,不過仍是建議經過訪問鏡像商店的方式搜索。注意,$mirror-name
須要替換爲想要搜索的鏡像名。
docker search $mirror-name
可使用如下指令拉取鏡像到本地,其中冒號後的 $tag
爲鏡像的版本標籤,若是省略冒號及以後的內容,則爲下載最新版本即 :latest
。版本標籤信息能夠在鏡像市場中查找到。
docker pull $mirror-name:$tag
注意,若下載的鏡像攜帶有版本標籤,則以後對這一鏡像的使用都須要攜帶版本標籤,不然會由於版本不一樣而再次下載。
查看全部鏡像可使用:
docker images
也可經過如下方式查看單個鏡像:
docker images $mirror-name
咱們能夠經過如下方式刪除鏡像,但此時須要保證沒有容器使用這一鏡像:
docker rmi $mirror-name
docker ps
docker ps -a
採用如下方法能夠查看容器的操做歷史和輸出:
docker logs $container-name
能夠經過如下方式生成一個基於某一鏡像的容器,注意,若是宿主機中沒有該鏡像則會先進行下載。務必注意鏡像標籤是否正確。
docker run $mirror-name:$tag
使用這一命令會使得容器在建立後自動啓動。
經過 docker ps -a
能夠看到容器的 ID 和 name,這二者均可以做爲後續對容器刪除、啓動、關閉及設置等操做的標識。使用 ID 時,只需輸入 ID 的前幾位便可(能與其餘容器區分)。
Docker 會爲其隨機生成 64 位長度的字符串做爲 ID,固然,咱們也能夠經過以下方式手動指定容器的名字,其中 $container-name
即爲指定的容器名。
docker run --name $container-name $mirror-name
docker start $container-name
docker stop $container-name
能夠經過如下方式,以交互的方式建立容器,固然也能夠在 $mirror-name
的前面加上 --name xxx
來指定容器的名字,在交互模式中,能夠輸入 exit
退出:
docker run -it $mirror-name
咱們可使用 -d
操做使容器在後臺運行:
docker run -d $mirror-name
容器在啓動後,若是沒有活動的前臺進程,容器會自動關閉。若要保持容器啓動狀態,能夠強制其執行一個前臺進程。具體可查看 參考連接 I 和 參考連接 II。
能夠用如下方式建立一個不自動關閉的 centos 鏡像:
docker run -it --name mycentos centos docker start mycentos // 此時能夠看到該容器沒有自動關閉 docker ps
咱們能夠經過如下方式對已經啓動的容器執行一些操做,其中 $container-name
能夠是容器的名字,也能夠是容器的 ID:
docker exec $container-name echo "hello" && echo "world"
也能夠經過如下方式進入交互模式:
docekr exec -it $container-name bash
其中,&&
是起到操做間鏈接的做用,詳細能夠查看 參考連接。此外,咱們也能夠在建立的容器的時候就使其執行一些操做:
docker run $mirror-name echo "hello world"
經過如下方式能夠查看容器的詳細信息,這些信息是採用 JSON 的格式展示的:
docker inspect $container-name
能夠在 rm
以後加入一個或多個容器名或容器 ID 進行批量刪除。
docker rm $container-name-1 $container-name-2 ...
可使用如下方法刪除所有容器:
docker rm $(docker ps -aq)
網絡的類別爲 none
,host
,bridge
三種,能夠經過如下方式查看:
docker network ls
顧名思義,此類網絡表示容器爲獨立個體,不與外部通訊。
此類網絡表示該容器與宿主機(安裝 Docker 的機器)共享網絡。
這是容器的默認網絡類型,網橋模式意味着容器間能夠互相通訊,而對外的通訊須要藉助宿主機,這一形式一般表現爲端口號的映射。
docker network inspect $network-name
經過這種方式能夠查看 JSON 格式的網絡類別,在 Containers
條目中能夠看到使用當前網絡類型的容器列表,注意 Containers
中只會顯示那些已經啓動的容器。
能夠經過如下方式建立一個網絡,其中,$network-driver
表示網絡類別,即 none
或 bridge
或 host
,而 $network-name
爲自定義的網絡名:
docker network create --driver $network-driver $network-name
若是省略 --driver $network-driver
則默認建立 bridge
類型的網絡。
咱們能夠建立自定義的網絡環境,並將一些容器放入這一網絡內,以此管理容器間的網絡連通狀況。這種局域網網段的模擬實際是由內部 DNS 實現的。如下羅列將容器添加或移除到某一網絡中的方法。
能夠經過如下方式將容器 $container-name
加入 $network-name
網絡中。注意,一個容器能夠屬於多個網絡。
docker network connect $network-name $container-name
以後,當容器啓動時,咱們就能夠在 docker network inspect $network-name
的 Containers
中看到這一容器了。
docker network disconnect $network-name $container-name
咱們也能夠在容器生成時指定網絡,使用以下方法:
docker run --network $network-name $mirror-name
咱們能夠經過如下方式查詢到容器的 IP 地址:
在容器交互模式中使用 ip addr
;
使用 docker inspect $container-name
使用 docker inspect $container-name | grep IPAddress
以後可使用 ping
指令測試容期間的網絡連通狀況。沒有 ping
命令的容器須要安裝 iputils
。
docker network rm $network-name
有時,咱們須要將容器的部分存儲映射到宿主機器件中,以便對配置文件、日誌文件、數據文件等進行備份或統一管理。
咱們能夠在建立時,將系統的某一目錄指定爲容器某一目錄的數據卷,其中 --volume
可使用 -v
縮寫:
docker run --volume /my/mac/dir:/container/dir $mirror-name
此時,容器內部的 /container/dir
將與宿主機的 /my/mac/dir
造成映射。
固然,咱們也能夠將文件與文件映射起來。
docker run --volume /my/mac/file:/container/file $mirror-name
在指定數據卷時,能夠省略宿主主機目錄,此時 Docker 會自動指定一個主機空間用以映射:
docker run --volume /container/dir $mirror-name
此外,還能夠選擇只讀方式,這樣文件或目錄的修改就只能在宿主機中進行了。只需添加 :ro
便可:
docker run --volume /my/mac/dir:/container/dir:ro $mirror-name
咱們能夠經過 docker inspect $container-name
,並在 Mounts
中看到數據卷的詳細狀況。
咱們能夠經過如下指令查看數據卷的狀況:
docker volume ls
當容器被刪除時,主機上的數據卷並不會被刪除,此時能夠經過如下指令查看那些沒有容器使用的數據卷,注意,這裏只會顯示那些由 Docker 自動指定的數據卷,即沒有手動指定主機映射目錄的數據卷:
docker volume ls -f dangling=true
順便,若是須要在刪除容器時一併刪除數據卷,可使用如下指令:
docker rm -v $container-name
有時咱們可能須要在建立容器時,選擇該容器的數據卷與以前的某容器相同,好比在面對多容器共享項目目錄空間這一需求時。此時咱們能夠經過如下方式實現:
docker run --volumes-from $container-name $mirror-name
可使用以下方式刪除數據卷,其中 $volume-id
能夠經過 docker volume ls
查看:
docker volume rm $volume-id
容器一旦建立後,再添加數據卷映射會比較麻煩,能夠查看 參考連接。
並且,這裏並不建議這麼作,建議的作法是將容器提交爲鏡像後,以此鏡像再次建立容器。
咱們能夠將容器的端口綁定到主機的某一端口上,已完成某些應用的需求,如將主機的 12345 端口綁定到容器的 80 端口上,這樣咱們對 localhost:12345
的訪問就至關於對容器 80 端口的訪問。
經過如下方式能夠實現端口綁定,其中 $host-port
爲宿主主機的端口,而 $container-port
爲容器的端口,如 12345:80
:
docker run -p $host-port:$container-port nginx
咱們也能夠只指定容器的端口號,此時 Docker 會自動分配一個主機上的端口號。
docker run -p $container-port nginx
對於 Nginx,官方鏡像在製做時指定暴露 80
和 443
端口用於 http
和 https
請求,對於這種在鏡像中暴露的端口,能夠在建立時使用如下方式所有指定:
docker run -P nginx
此時,Docker 會自動分配主機上的兩個端口分別映射容器的 80
和 443
端口。自動分配的數量與鏡像中暴露的端口數量對應。
咱們能夠在 docker ps -a
中的 PORTS
欄看到端口映射狀況。注意只有處於運行中的容器纔會有實際的端口映射。
此外,咱們還可使用如下指令查看某一容器的端口映射:
docker port $container-name
建立一個容器時,可能須要對多項參數進行限制,好比指定網絡、指定數據卷、指定端口等等。並且,有時咱們可能須要同時使用多個容器共同支撐應用,好比 Nginx 容器、php & php-fpm 容器、MySQL 容器、Redis 容器等。
若是每次都使用各類參數,按某種順序依次啓動容器(容器之間可能存在前後順序,好比要先啓動 PHP 而後再啓動 Nginx 容器)的話,會形成不少繁瑣的操做。爲了解決這個問題,咱們可使用 docker-compose。
執行如下指令查看 docker-compose 能夠執行的指令:
docker-compose --help
docker-compose 依賴一個 docker-compose.yml
文件,用以指定容器數據卷、網絡等。
.yml
文件遵循 YAML 語法,這是一種使用縮進的語法。詳細可見 YAML 語言教程。
下面給出一個簡單的樣例,用以說明 docker-compose 的用法
version: '2.0' services: # 啓用一個鏡像爲 nginx 的容器並命名爲 web1 web1: image: nginx # 開啓 80 和 443 端口,實際映射端口由 Docker 指定 ports: - "80" - "443" # 將該容器加入 mynetwork 中 networks: - "mynetwork" # 指定該容器要在 web2 容器啓動以後啓動,且在其中止前中止 depends_on: - web2 web2: image: nginx ports: - "33333:80" networks: - "mynetwork" - "bridge" volumes: - "/mnt" networks: # 建立一個驅動爲 bridge 的網絡,命名爲 mynetwork mynetwork: driver: bridge
其中,容器的實際名字爲 .yml 文件所在目錄名_.yml 文件中指定的名字_序號
,如 mydir_web1_1
。可是,在容器內部,可使用 mydir_web1_1
也可使用 web1
做爲域名訪問另外一主機,這對於以後多容器共同支撐 web 服務是相當重要的。
更多的 .yml
文件的寫法能夠參考 [YAML 模板文件][9]
首先,咱們須要有一個名爲 docker-compose.yml
或 docker-compose.yaml
的文件,並進入該文件所在目錄下,經過如下命令生成並啓動:
docker-compose up
Docker 會根據 docker-compose.yml
中的內容建立網絡、數據卷和容器。
固然也能夠加入參數 -d
使其生成後在後臺運行:
docker-compose up -d
中止容器可使用:
docker-compose stop
再次運行容器可使用
docker-compose start
docker-compose logs
經過如下命令能夠刪除容器,但不會刪除以前建立的網絡
docker-compose rm
若想既刪除容器,又刪除網絡,可使用:
docker-compose down
注意,數據卷的刪除仍要使用以前刪除數據卷的方法。
咱們對使用某一鏡像的容器作了修改,好比在使用 centos 這一鏡像建立的容器中安裝了 nginx,此時咱們能夠將這一容器生成爲一個新的鏡像,這以後就能夠經過這個新鏡像建立其餘容器,而這些容器也一樣已經安裝了 nginx。
生成鏡像可使用以下方式:
docker commit -m $commit-msg -a $author $container-id $namespace/$mirror-name:$tag
如:
docker commit -m 'install nginx' -a 'dailybird' abcd1234 dailybird/nginx:test
以後即可以經過 docker images
查看已經建立的鏡像了。
咱們能夠將鏡像提交到官方倉庫中,這樣就能夠像最初獲取鏡像的方式同樣得到本身製做的鏡像了。
首先,咱們須要在 Docker Hub 上註冊帳戶:
https://hub.docker.com/
而後使用如下命令登陸:
docker login
以後會提示輸入用戶名和密碼,顯示登陸成功後,用如下方式推送:
docker push $namespace/$mirror-name:$tag
因爲國內訪問 Docker Hub 的速度較慢,咱們也可使用 DaoCloud 或阿里雲的 Docker 服務,具體的推送方法能夠訪問以前給出的網址,參照其中的方法便可。
使用已有容器建立鏡像的方式當然可行,可當咱們須要再次對鏡像修改時,就須要再次生成容器、進行配置修改或軟件安裝、提交鏡像。此外,不斷在原有提交鏡像的基礎上修改提交會存在兩個問題:
累積的修改條目不夠直觀,可能以後本身也不知道對原有鏡像作了什麼修改;
不斷修改的過程在 Docker 看來是增量更新的過程。這一次的修改至關於在上一次的基礎上增長了一個只讀層用於記錄本次的修改狀況。而只讀層的數量是有限的,也就意味着這種修改和提交的方式的操做次數是受限的。
那麼,有沒有一種更好的方式能夠實現鏡像的生成呢?類比 docker-compose.yml
,咱們可使用另外一種相似配置文件的方式來指導鏡像的生成,這就是 Dockerfile
。
Dockerfile 能夠指定新鏡像的原鏡像來源、對原鏡像的操做、環境變量,以及以此建立容器時執行的指令等。
# 新鏡像基於的原鏡像 FROM centos:centos6.8 # 指明維護者 MAINTAINER dailybird <dailybird@mail.com> # 設置一些環境變量,使用 \ 表示鏈接多個設置 ENV NGINX_VERSION 1.11.11 \ TEST_ENV hello # 指定暴露的端口號, EXPOSE 80 443 # 在原鏡像基礎上進行的修改 RUN yum install -y wget iputils \ && wget http://nginx.org/download/nginx-1.11.11.tar.gz # 以此鏡像建立並啓動時,容器執行的指令,一般用於啓動服務 CMD ["echo", "hello world"]
好比使用如下配置能夠在 centos
中安裝 nginx
:
FROM centos:centos6.8 MAINTAINER dailybird <dailybird@mail.com> EXPOSE 80 443 RUN cd / \ && mkdir data \ && cd data \ && mkdir nmp \ && cd nmp \ && yum install -y wget pcre-devel gcc gcc-c++ \ ncurses-devel perl make zlib zlib-devel \ openssl openssl--devel iputils \ && wget http://nginx.org/download/nginx-1.11.11.tar.gz \ && tar zxf nginx-1.11.11.tar.gz \ && cd nginx-1.11.11 \ && ./configure --prefix=/usr/local/nginx \ && make && make install && make clean \
更多的 Dockerfile 指令能夠參考 Dockerfile 指令。
首先,咱們須要新建一個名爲 Dockerfile
的文件(沒有後綴),並寫入一些配置內容。而後在該文件的目錄中,經過如下指令建立鏡像:
docker build --tag $namespace/$mirror-name:$tag $dockerfile-dir
其中,$dockerfile-dir
爲 Dockerfile
所在目錄,好比執行:
docker build --tag dailybird/nginx-demo:demo ./
等待一段時間以後,即可經過 docker images
看到新建立的鏡像了。
當咱們須要啓動一個新鏡像時,能夠先將此鏡像建立出來,而後在 docker-compose.yml
文件中經過 image
指定新鏡像;也能夠直接經過如下方式將這兩個步驟合併:
version: '2.0' services: web1: # build 後的參數爲 Dockerfile 文件所在的目錄位置,替換原先的 image build: ./ ports: - "80" networks: - "mynetwork" # ... # 其餘配置
此後,能夠經過如下指令建立容器:
docker-compose build docker-compose up
或者,直接執行:
docker-compose up --build
這時,Docker 會自動建立一個鏡像,並以此建立容器。
關於 Docker 還有不少內容,好比備份、集羣、插件等。不過這些就留到進一步研究以後再撰文吧。
有時可能遇到以下 Docker 報錯:
WARNING: Error loading config file:/home/user/.docker/config.json - stat /home/user/.docker/config.json: permission denied
此時,能夠經過如下方法解決:
sudo chmod -R g+rwx /your/path/to/.docker/