Docker 基礎 - 1

東風微鳴發表於2023-01-24

映象

獲取映象

docker pull

檢視映象資訊

docker images

docker inspect <images id> # 獲取映象的詳細資訊

搜尋映象

docker search

刪除映象

docker rmi

當一個映象擁有多個標籤,docker rmi 只是刪除該映象指定的標籤,並不影響映象檔案
當映象只剩下一個標籤時,再使用會徹底刪除該映象
先刪除該映象的所有容器,再刪除映象

建立映象

2 種方法:

  • 基於已有映象的容器建立
  • 基於 Dockerfile 建立(推薦)

基於已有映象的容器建立

docker commit

-a: 作者資訊
-m: 提交資訊
-p 提交時暫停容器執行
-c changelist

存出和載入映象

存出sudo docker save -o ubuntu_16.04.tar ubuntu:16.04

載入sudo docker load --input ubuntu_16.04.tar 或者 sudo docker load < ubuntu_16.04.tar

匯入映象,以及其相關的後設資料資訊(包括標籤等)

容器

建立容器

使用互動式來執行容器:sudo docker run -it ubuntu:latest /bin/bash

docker run在後臺執行的標準操作:

  1. 檢查本地是否存在指定的映象, 不存在就從公有倉庫下載
  2. 利用映象建立啟動一個容器
  3. 分配一個檔案系統,並在只讀的映象層外面掛載一層可讀寫層
  4. 從宿主主機配置的網橋介面中橋接一個虛擬介面到容器中去。
  5. 從地址池配置一個 IP 地址給容器
  6. 執行使用者指定的應用程式
  7. 執行完畢後容器被終止

守護態執行

sudo docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"

透過docker logs命令獲取容器的輸出資訊:sudo docker -tf logs 2855b4d76ccb

-t: 列印時間戳
-f: 重新整理日誌到最後
2855b4d76ccb: 容器id

終止容器

sudo docker stop 2855b4d76ccb

檢視所有容器的資訊:sudo docker ps -a

處於終止狀態的容器,可以透過 docker start 命令來重新啟動:sudo docker start 2855b4d76ccb

重啟容器:sudo docker restart 2855b4d76ccb

進入容器

attach指令

sudo docker attach 2855b4d76ccb

當多個視窗同時 attach 到同一個容器時, 所有視窗會同步顯示。當某個視窗因命令阻塞時,其他視窗也無法執行操作。

exec 命令

sudo docker exec -ti 2855b4d76ccb /bin/bash

刪除容器

sudo docker rm 2855b4d76ccb

-f 強制刪除執行中的容器
-l 刪除容器連結,但保留容器
-v 刪除容器掛載的資料卷

匯入/匯出容器

匯出

sudo docker export 2855b4d76ccb > test.tar

可以將這些檔案傳輸到其他機器上, 在其他機器上透過匯入命令實現容器遷移

匯入

cat test.tar | sudo docker import - test/ubuntu:v1.0

docker load 匯入映象儲存檔案到本地的映象庫
docker import 匯入一個容器快照到本地映象庫

區別:

容器快照檔案將丟棄所有的歷史記錄和後設資料資訊(僅儲存容器當時的快照狀態),匯入時可以重新指定標籤等後設資料資訊。
映象儲存檔案將儲存完整記錄, 體積也大。

倉庫

Docker Hub

登入

docker login

搜尋

docker search

docker tag

sudo docker tag ubuntu:14.04 10.0.2.2:5000/test

自動建立

步驟:

  1. 登入 Docker Hub, 連線 GitHub 到 Docker
  2. 在Docker Hub 中配置自動建立:https://hub.docker.com/add/automated-build/caseycui/
  3. 選取一個目標網站專案(需要含 Dockerfile)和分支
  4. 指定 Dockerfile 的位置,並提交建立
  5. 之後,可以在 Docker Hub 的“自動建立”頁面中跟蹤每次建立的狀態。

建立和使用私有倉庫

使用 registry 映象建立私有倉庫

sudo docker -d -p 5000:5000 -v /opt/docker/registry/:/tmp/registry registry

監聽埠對映到 5000,docker 容器中的 /tmp/registry 被對映到本地的 /opt/docker/registry/ 上。

管理私有倉庫映象

  • 修改 tag 的 REGISTRYHOST sudo docker tag ubuntu:latest 172.17.0.1:5000/test
  • 使用 docker push 上傳 sudo docker push 172.17.0.1:5000/test
  • 使用docker pull 下載 sudo docker pull 172.17.0.1:5000/test

資料管理

兩種方式:

  • 資料卷(Data Volumes)
  • 資料卷容器(Data Volume Containers)

資料卷

特性:

  • 可以在容器間共享和重用
  • 對資料卷的修改會立馬生效
  • 對資料卷的更新, 不會影響容器
  • 卷會一直存在, 直到沒有容器使用

類似 Linux 的 mount 操作

掛載一個主機目錄作為資料卷

sudo docker run -v /src/webapp:/opt/webapp training/webapp python app.py

載入主機的/src/webapp 目錄到容器的 /opt/webapp 目錄.

主機目錄必須是絕對路徑

預設許可權是讀寫(rw), 可以設定為只讀(ro) /src/webapp:/opt/webapp:ro

資料卷容器

資料卷容器其實就是普通的容器, 專門用它提供資料卷供其他容器掛載使用.

  1. 建立一個資料卷容器: sudo docker run -it -v /dbdata --name dbdata ubuntu

  2. 在其他容器中使用 volumes-from 來掛載 dbdata 容器中的資料卷.

    
    
    sudo docker run -it --volumes-from dbdata --name db1 ubuntu
    
    
    sudo docker run -it --volumes-from dbdata --name db2 ubuntu
    
    
    

    3個容器任何一方在該目錄寫入, 其他容器都可以看到。
    如果刪除了容器, 資料卷並不會自動刪除. 如果要刪除資料卷, 必須在刪除最後一個掛載著它的容器時顯式使用 docker rm -v 命令來指定同時刪除關聯的容器

利用資料卷容器遷移資料

備份

sudo docker run --volumes-from dbdata -v $(pwd):/backup --name worker ubuntu tar cvf /backup/backup.tar /dbdata

恢復

sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar

網路基礎配置

埠對映實現訪問容器

sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

-P: 對映到隨機埠

檢視埠對映配置

sudo docker port loving_montalcini

容器互聯實現容器間通訊

容器的連線(linking)系統, 它會在源和接收容器之間建立一個隧道, 接收容器可以看到源容器指定的資訊.

連線系統依據容器的名稱來執行.

在執行 docker run 的時候如果新增 --rm 標記, 則容器在終止後會立即刪除. --rm-d 無法同時使用.

容器互聯

sudo docker run -d --name db training/postgres  # 建立一個新的資料庫容器
sudo docker run -d -P --name web --link db:db training/webapp python app.py  # --link name:alias alias是連線的別名

Docker透過2種方式為容器公開連線資訊:

  • 環境變數
  • 更新 /etc/hosts 檔案

使用 env 命令檢視web容器的環境變數:

$ docker exec web env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=62b19d3b5add
DB_PORT=tcp://172.17.0.2:5432
DB_PORT_5432_TCP=tcp://172.17.0.2:5432
DB_PORT_5432_TCP_ADDR=172.17.0.2
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/web/db
DB_ENV_PG_VERSION=9.3
HOME=/root

/etc/hosts 檔案:

$ docker exec web cat /etc/hosts

127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

172.17.0.2      db 4288c4f9ad47
 
172.17.0.3      62b19d3b5add  # 本容器

也可以透過 ping 來測試:

$ docker exec web ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.083 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.054 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.053 ms
64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.055 ms
64 bytes from 172.17.0.2: icmp_seq=6 ttl=64 time=0.057 ms

使用 Dockerfile 建立映象

基本結構

  • 基礎映象資訊
  • 維護者資訊
  • 映象操作指令
  • 容器啟動時執行指令

指令

FROM

第一條指令必須為 FROM 指令

MAINTAINER(已棄用)

制定維護者資訊. 以後可以用 LABEL maintainer="CaseyCui cuikaidong@foxmail.com"

RUN

兩種格式:

  • RUN <command> bash格式, 命令在bash中執行, 預設在Linux是 /bin/sh -c 在windows上是 cmd /S /C
  • RUN ["executable", "param1", "param2"] (用 docker exec 執行)

每條RUN指令將在當前映象基礎上執行指定命令, 並提交為新的映象.

最佳實踐:

apt-get安裝:

RUN apt-get update && apt-get install -y --no-install-recommends \
    aufs-tools \
    automake \
    build-essential \
    curl \
    dpkg-sig \
    libcap-dev \
    libsqlite3-dev \
    mercurial \
    reprepro \
    ruby1.9.1 \
    ruby1.9.1-dev \
    s3cmd=1.1.* \
&& rm -rf /var/lib/apt/lists/*

apt-get update && apt-get install 合用

apt-get install -y --no-install-recommends 不安裝其他推薦的包, -no-install-suggests 也可以加上

ruby1.9.1 s3cmd=1.1.* 安裝指定版本的包

rm -rf /var/lib/apt/lists/* 刪除軟體包殘留

## a few minor docker-specific tweaks
## see https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap
RUN set -xe \
    \
## https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L40-L48
    && echo '#!/bin/sh' > /usr/sbin/policy-rc.d \
    && echo 'exit 101' >> /usr/sbin/policy-rc.d \
    && chmod +x /usr/sbin/policy-rc.d \
    \
## https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L54-L56
    && dpkg-divert --local --rename --add /sbin/initctl \
    && cp -a /usr/sbin/policy-rc.d /sbin/initctl \
    && sed -i 's/^exit.*/exit 0/' /sbin/initctl \
    \
## https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L71-L78
    && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \
    \ 
## https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L85-L105
    && echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean \
    && echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean \
    && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean \
    \
## https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L109-L115
    && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages \
    \ 
## https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L118-L130
    && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes \
    \ 
## https://github.com/docker/docker/blob/9a9fc01af8fb5d98b8eec0740716226fadb3735c/contrib/mkimage/debootstrap#L134-L151
    && echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests

set -xe 除錯模式, 返回非 0 (即不成功) 就退出

CMD

支援三種格式:

  • CMD ["executable","param1","param2"] 使用 docker exec 執行, 推薦方式
  • CMD ["param1","param2"] 作為 ENTRYPOINT 的預設引數
  • CMD command param1 param2 bash

指定啟動容器時執行的命令, 每個 Dockerfile 只能有一條 CMD 命令.

EXPOSE

EXPOSE 80 8443

暴露的埠號, 供互聯絡統使用. 在啟動時可以透過 -P-p 來指定對映

ENV

ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

ADD

推薦只在 src 為 tar 檔案時(會自動解壓)使用. 其他時候使用 COPY. 不推薦使用 URL 的方式.

COPY

COPY <src> <dest> 當使用本例目錄為 src 時, 推薦使用 COPY

ENTRYPOINT

兩種格式:

  • ENTRYPOINT ["executable", "param1", "param2"] exec 格式
  • ENTRYPOINT command param1 param2 bash 格式

VOLUME

建立一個可以從本地主機或其他容器掛載的掛載點, 一般用來存放資料庫和需要保持的資料等.

USER

指定執行容器時的使用者名稱或 UID, 後續的 RUN 也會使用指定使用者.

當服務不需要管理員許可權時, 可以透過該命令指定執行使用者.

要臨時獲取管理員許可權推薦使用 gosu , 不推薦sudo

WORKDIR

為後續的 RUN CMD ENTRYPOINT 指令配置工作目錄.

ONBUILD

ONBUILD [Dockerilfe的指令]

配置當所建立的映象作為其他新建立映象的基礎映象時, 所執行的操作指令.

使用 ONBUILD 指令的映象, 推薦在 tag 中註明, 如 ruby:1.9-onbuild

建立映象

docker build [選項] 路徑

實現:

  1. 讀取指定路徑下(包括子目錄)的 Dockerfile
  2. 將該路徑下所有內容傳送給 Docker 服務端
  3. 由服務端來建立映象

一般建議放置 Dockerfile 的目錄為空目錄

可以透過 .dockerignore 檔案來讓 Docker 忽略路徑下的目錄和檔案.

## comment
*/temp*
*/*/temp*
temp?

指令示例: sudo docker build -t build_repo/first_image /tmp/docker_builder/

三人行, 必有我師; 知識共享, 天下為公. 本文由東風微鳴技術部落格 EWhisper.cn 編寫.