Docker學習筆記--CLI和Registry

Docker概覽

Docker架構

Docker學習筆記--CLI和Registry
Docker採用client-server架構,client和daemon間使用REST API進行通信。client和daemon能夠運行在相同或不一樣的機器。daemon間也能夠經過Docker API通信。
Docker學習筆記--CLI和Registry
Docker Registry存儲image,Docker Hub是默認的公有Registry,也可配置使用私有Registry。
使用Docker時會涉及image、container、network、volume、plugin等對象。html

  • Image是用來建立Container的只讀模板。一個Image能夠創建在另外一個Image之上,使用Dockerfile文件配置image。Dockerfile的每一指令建立一個image layer,當更改Dockerfile重建image時,僅更改的layer被重建。
  • Container是Image的運行實例。

Docker版本

  • Community Edition (CE)
  • Enterprise Edition (EE)
Capabilities Community Edition Enterprise Edition Basic Enterprise Edition Standard Enterprise Edition Advanced
Container engine and built in orchestration, networking, security yes yes yes yes
Certified infrastructure, plugins and ISV containers yes yes yes
Image management yes yes
Container app management yes yes
Image security scanning yes

自17年3月,Docker版本號採用YY.mm.patch格式,YY.mm表明年月。node

安裝和卸載

在CentOS 7或RHEL 7上可直接使用yum安裝,以下:python

# yum install docker
# systemctl enable docker
# systemctl start docker

docker配置文件位置:
/etc/sysconfig/docker
/etc/docker目錄linux

安裝官方最新版本docker,步驟以下:nginx

卸載舊版本

如安裝過Docker先卸載,舊版本稱爲docker或docker-engine,:redis

# yum remove docker docker-client docker-client-latest docker-common \
           docker-latest docker-latest-logrotate docker-logrotate \
           docker-selinux docker-engine-selinux docker-engine

目錄/var/lib/docker/下的內容不會刪除,其中包含images、containers、volumes、networks等。docker

安裝Docker CE

  1. 更新系統
# yum update

安裝最新版的container-selinuxshell

# yum install -y http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.66-1.el7.noarch.rpm

如未更新container-selinux,在安裝Docker CE時可能會顯示以下錯誤:apache

Error: Package: docker-ce-18.06.0.ce-3.el7.x86_64 (docker-ce-edge)
           Requires: container-selinux >= 2.9
  1. 安裝必須的Package

yum-utils提供yum-config-manager工具,用來配置Docker Repository;devicemapper storage driver須要device-mapper-persistent-data和lvm2json

# yum install -y yum-utils device-mapper-persistent-data lvm2
  1. 配置Docker Repository
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

默認stable repository是啓用的,若要啓用edge或test repository(stable repository是必須的),執行以下命令:

# yum-config-manager --enable docker-ce-edge
# yum-config-manager --enable docker-ce-test
  1. 安裝Docker CE
# yum install docker-ce
# systemctl enable docker
# systemctl start docker
  1. 驗證docker安裝
# docker info
# docker --version
# docker version

運行hello-world:

# docker run hello-world

成功後輸出以下:

Unable to find image 'hello-world:latest' locally
Trying to pull repository docker.io/library/hello-world ...
latest: Pulling from docker.io/library/hello-world
1b930d010525: Pull complete
Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535
Status: Downloaded newer image for docker.io/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.

查看image和container:

# docker images
# docker ps
  1. 用戶管理

Docker Daemon綁定了Unix socket,而不是TCP端口,默認Unix socket由root和sudo權限的用戶擁有。爲了運行docker命令時不使用sudo,建立Unix group "docker"(Docker安裝後建立了docker group),將用戶添加到docker group便可。當docker daemon啓動時,讓docker group有讀/寫Unix Socket權限。

# groupadd docker
# usermod -aG docker $USER

執行以上命令後需從新登陸或重啓。

卸載Docker CE

# yum remove docker-ce

Images、 containers、 volumes、customized configuration files不會自動刪除,執行如下命令刪除:

# rm -rf /var/lib/docker

Docker CLI

CLI Description
Engine CLI The main CLI for Docker, includes all docker and dockerd commands
Compose CLI The CLI for Docker Compose, which allows you to build and run multi-container applications
Machine CLI Manages virtual machines that are pre-configured to run Docker
DTR CLI Deploy and manage Docker Trusted Registry
UCP CLI Deploy and manage Universal Control Plane

Docke支持多方面的CLI,下面僅涉及Engine CLI docker。

運行不帶任何參數的docker命令或docker help,可列出全部可用的docker命令

爲了查看某一命令的幫助,執行以下命令:

$ docker run --help

option參數能夠組合在一塊兒:

docker run -i -t --name test busybox sh

能夠寫成:

docker run -it --name test busybox sh

docker run

$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

啓動docker container有兩種模式:Detached、Foreground,默認是Foreground模式。
Foreground模式
Options:

-a=[]         : Attach to `STDIN`, `STDOUT` and/or `STDERR`
-t              : Allocate a pseudo-tty
--sig-proxy=true: Proxy all received signals to the process (non-TTY mode only)
-i              : Keep STDIN open even if not attached

-i -t組合在一塊兒使用,能夠與容器進行交互:

$ docker run -a stdin -a stdout -i -t ubuntu /bin/bash

運行以上命令後,會執行如下操做:

  1. 如本地沒有ubuntu image,將從registry獲取,至關於手動執行docker pull ubuntu
  2. Docker建立新的容器,至關於運行docker container create
  3. Docker給容器分配可讀寫的文件系統
  4. Docker建立網絡接口鏈接容器到默認網絡
  5. Docker啓動容器並執行/bin/bash

容器啓動後,能夠執行shell命令,以下:

root@f7cbdac22a02:/# hostname
root@f7cbdac22a02:/# cat /etc/hosts
root@f7cbdac22a02:/# yum install -y vim
  1. 輸入exit,終止/bin/bash,容器中止但不會被刪除,能夠從新啓動。
root@f7cbdac22a02:/# exit

Detached模式
當指定-d選項後,啓用Detached模式,container將在後臺運行。

$ docker run -d -p 80:80 my_image nginx -g 'daemon off;'

Container identification
有三種類型:

Identifier type Example value
UUID long identifier 「f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778」
UUID short identifier 「f78375b1c487」
Name 「evil_ptolemy」

當運行container時,如未使用--name指定容器名,daemon將生成一隨機字符串做爲名字。

Attach to and detach from a running container

$ docker run -d --name topdemo ubuntu /usr/bin/top -b
$ docker attach topdemo

docker commit

使用docker commit能夠從container建立image。

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Options

Name, shorthand Default Description
--author , -a Author (e.g., 「John Hannibal Smith hannibal@a-team.com」)
--change , -c Apply Dockerfile instruction to the created image
--message , -m Commit message
--pause , -p true Pause container during commit

先建立一個Container

$ docker run -t -i training/sinatra /bin/bash

而後運行shell腳本更新container

$ root@0b2616b0e5a8:/# yum install vim

更新完畢後,運行exit退出。
最後使用docker commit建立image:

$ docker commit -m "Added json gem" -a "Kate Smith" 0b2616b0e5a8 ouruser/sinatra:v2

還可使用--change修改後再建立image:

$ docker commit --change='CMD ["apachectl", "-DFOREGROUND"]' -c "EXPOSE 80" c3f279d17e0a  svendowideit/testimage:version4

docker build

從Dockerfile建立image,這是最經常使用的方式。

docker build [OPTIONS] PATH | URL | -

下面演示從Dockerfile建立image:
Dockerfile
建立一個空目錄,在其內建立名爲Dockerfile的文件,內容以下:

# Use an official Python runtime as a parent image
FROM python:2.7-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
ADD . /app

# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

Dockerfile引用了文件app.py 和 requirements.txt,下面在相同目錄建立這兩個文件:
requirements.txt

Flask
Redis

app.py

from flask import Flask
from redis import Redis, RedisError
import os
import socket

# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)

app = Flask(__name__)

@app.route("/")
def hello():
    try:
        visits = redis.incr("counter")
    except RedisError:
        visits = "<i>cannot connect to Redis, counter disabled</i>"

    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>" \
           "<b>Visits:</b> {visits}"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

Build

$ docker build -t friendlyhello .

Container相關命令

Command Description
docker attach Attach local standard input, output, and error streams to a running container
docker container Manage containers
docker cp Copy files/folders between a container and the local filesystem
docker create Create a new container
docker diff Inspect changes to files or directories on a container’s filesystem
docker exec Run a command in a running container
docker export Export a container’s filesystem as a tar archive
docker kill Kill one or more running containers
docker logs Fetch the logs of a container
docker pause Pause all processes within one or more containers
docker port List port mappings or a specific mapping for the container
docker ps List containers
docker rename Rename a container
docker restart Restart one or more containers
docker rm Remove one or more containers
docker run Run a command in a new container
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 top Display the running processes of a container
docker unpause Unpause all processes within one or more containers
docker update Update configuration of one or more containers
docker wait Block until one or more containers stop, then print their exit codes

示例:
List containers

$ docker ps -a

-a 顯示全部的container,默認僅顯示運行的container

Stop one or more running containers

$ docker stop CONTAINER [CONTAINER...]

Remove one or more containers

$ docker rm CONTAINER [CONTAINER...]

Remove all containers

$ docker rm `docker ps -a -q`

Start one or more stopped containers

$ docker start CONTAINER [CONTAINER...]

Fetch the logs of a container

$ docker logs -f --until=2s my_container

Run a command in a running container

$ docker exec -d my_container touch /tmp/execWorks

Image相關命令

Command Description
docker build Build an image from a Dockerfile
docker commit Create a new image from a container’s changes
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 load Load an image from a tar archive or STDIN
docker manifest Manage Docker image manifests and manifest lists
docker pull Pull an image or a repository from a registry
docker push Push an image or a repository to a registry
docker rmi Remove one or more images
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 tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
docker trust Manage trust on Docker images

示例:
pull an image

$ docker pull hello-world

Push an image

$ docker push hello-world:latest

List images

$ docker images

Search images

$ docker search centos

Remove one or more images

$ docker rmi IMAGE [IMAGE...]

Remove all images

$ docker rmi `docker images -a -q`

Registry命令

Command Description
docker login Log in to a Docker registry
docker logout Log out from a Docker registry
docker pull Pull an image or a repository from a registry
docker push Push an image or a repository to a registry

搭建私有Registry

docker經常使用命令結構:

docker <command> <registry-hostname>:<registry-port>/<namespace>/<image>:<tag>

默認Registry爲Docker Hub,默認namespace爲/library,如下三個命令效果相同:

# docker pull hello-world
# docker pull docker.io/hello-world
# docker pull docker.io/library/hello-world

使用Docker中國官方鏡像registry.docker-cn.com能夠享受到更快的下載速度和更強的穩定性,但只包含流行的公有鏡像。

# docker pull registry.docker-cn.com/library/hello-world

能夠配置Docker守護進程默認使用Docker中國官方鏡像,這樣無需在每次拉取時指定registry.docker-cn.com,修改文件/etc/docker/daemon.json添加registry-mirrors鍵值:

{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}

保存後重啓Docker以使配置生效。

初識Registry

  1. 使用官方registry鏡像建立私有Registry
# mkdir /mnt/registry/docker
# docker run -d -p 5000:5000  --restart always -v /mnt/registry:/var/lib/registry --name registry registry

參數說明:
--restart always 容器異常退出或重啓docker後自動重啓容器
-v /mnt/registry:/var/lib/registry 綁定/mnt/registry到容器/var/lib/registry目錄(存放鏡像文件的目錄)來實現數據持久化

selinux
如系統啓用了selinux,要爲/mnt/registry設置selinux安全上下文類型,以下:

# semanage fcontext -a -t container_file_t "/mnt/registry(/.*)?"
# restorecon -R -v /mnt/registry
  1. 上傳image

爲image打標籤後上傳到倉庫:

$ docker tag hello-world localhost:5000/hello-world:latest
$ docker push localhost:5000/hello-world:latest

tag語法:
Usage: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

也可使用IMAGE ID:

$ docker tag fce289e99eb9 localhost:5000/hello-world:latest

如系統啓用了selinux,但未設置安全上下文類型,上傳時會一直retry,報以下錯誤(可運行journalctl -xe查看緣由):

SELinux is preventing /bin/registry from add_name access on the directory docker.

*****  Plugin catchall_labels (83.8 confidence) suggests   *******************

If you want to allow registry to have add_name access on the docker directory
Then you need to change the label on docker
Do
# semanage fcontext -a -t FILE_TYPE 'docker'
where FILE_TYPE is one of the following: container_file_t, container_var_lib_t, nfs_t, svirt_home_t, tmpfs_t, virt_home_t.
Then execute:
restorecon -v 'docker'
  1. 從本地registry運行容器
$ docker run localhost:5000/hello-world
  1. 查看registry中的image

列出全部image:

curl http://localhost:5000/v2/_catalog

列出hello-world image:

curl http://localhost:5000/v2/hello-world/tags/list
  1. 外部訪問registry

經過上面方式建立的registry其協議爲http,是不安全的,只適用於本地使用,若要從外部訪問registry,須要編輯/etc/docker/daemon.json,增長insecure-registries,以下:

{
  "insecure-registries": ["192.168.122.1:5000"]
}

配置完畢後需重啓docker。

SSL Registry

  1. 獲取證書

以自簽名證書爲例,Registry URL爲registry.itrunner.org,生成自簽名證書:

$ cd /mnt/registry
$ mkdir certs
$ openssl req -newkey rsa:2048 -nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt -subj /C=CN/ST=Beijing/L=Beijing/CN=registry.itrunner.org/OU=itrunner/O=itrunner/emailAddress=sjc-925@163.com

一樣,如系統啓用了selinux,需給certs目錄指定安全上下文:

# semanage fcontext -a -t container_file_t "certs(/.*)?"
# restorecon -R -v certs

每臺使用這個Registry的主機都需將自簽名證書拷貝到/etc/docker/certs.d/registry.itrunner.org目錄下:

# mkdir /etc/docker/certs.d/registry.itrunner.org
# cp certs/domain.crt /etc/docker/certs.d/registry.itrunner.org
  1. 刪除當前運行的Registry
$ docker stop registry
$ docker rm registry
  1. 配置證書從新運行Registry
$ docker run -d --restart always --name registry -v /mnt/registry:/var/lib/registry \
-v "$(pwd)"/certs:/certs \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
-p 443:443 \
registry
  1. 測試
$ curl -k https://registry.itrunner.org/v2/
$ docker tag hello-world registry.itrunner.org/hello-world
$ docker push registry.itrunner.org/hello-world
$ docker pull registry.trunner.org/hello-world

Registry Proxy

每次都從遠程Registry獲取image浪費網絡資源,效率低下。雖然咱們能夠先從遠程pull,再push到私有Registry,但這樣操做很是煩瑣。Registry Proxy能夠本地存儲image,減小了重複的pull操做。Registry Proxy不支持push。
此次咱們使用配置文件運行registry,執行如下命令獲取默認配置文件:

$ docker run -it --rm --entrypoint cat registry /etc/docker/registry/config.yml > config.yml

文件內容以下:

version: 0.1
log:
  fields:
    service: registry
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

增長proxy配置:

version: 0.1
log:
  fields:
    service: registry
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: 0.0.0.0:443
  headers:
    X-Content-Type-Options: [nosniff]
  tls:
    certificate: /var/lib/registry/certs/domain.crt
    key: /var/lib/registry/certs/domain.key
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
proxy:
  remoteurl: https://registry-1.docker.io

修改/etc/docker/daemon.json:

{
  "registry-mirrors": ["https://registry.itrunner.org"]
}

重啓docker後運行registry:

$ docker run -d --restart always --name registry-proxy -p 443:443 -v /mnt/registry:/var/lib/registry \
registry /var/lib/registry/config.yml

測試:

$ docker pull hello-world

查看proxy:

$ curl -k https://registry.itrunner.org/v2/_catalog
{"repositories":["library/hello-world"]}

能夠看到hello-world已保存到proxy中。

搭建Nexus私服

除默認Registry外,使用docker時必須指定Registry域名,可否像Maven同樣統一使用一個倉庫呢?Nexus 3支持Docker Repository,同Maven同樣分爲三種類型:group、hosted、proxy。hosted至關於私有Registry,用來存儲公司內部image;proxy爲代理Registry;group能夠將hosted、proxy、group三者組合在一塊兒。

Docker Proxy

下面建立docker.io的代理,依次點擊Repository -> Repositories -> Create repository -> docker(proxy) :
Docker學習筆記--CLI和Registry
參數說明:
Repository Connectors Docker Client鏈接Repository的地址,僅需指定HTTP或HTTPS端口,若使用HTTPS則啓動Nexus時也需使用HTTPS。通常不直接訪問Proxy,而是經過group,此處沒必要配置。
Force basic authentication 若啓用則禁止匿名訪問,需提供nexus帳號
Enable Docker V1 API 通常沒必要啓用V1 API,如今經常使用的是V2 API
Docker學習筆記--CLI和Registry
Remote Repository:https://registry-1.docker.io ,Docker Index:Use Docker Hub
Docker學習筆記--CLI和Registry

Docker Hosted

依次點擊Repository -> Repositories -> Create repository -> docker(hosted) :
Docker學習筆記--CLI和Registry

Docker Group

依次點擊Repository -> Repositories -> Create repository -> docker(group) :
Docker學習筆記--CLI和Registry

匿名訪問

首先確認是否啓用了匿名訪問,依次點擊Security -> Anonymous:
Docker學習筆記--CLI和Registry
其餘配置保持默認值。
而後建立docker匿名用戶角色並授予適當權限,依次點擊Security -> Roles -> Create role - Nexus role:
Docker學習筆記--CLI和Registry
接下來將角色授予匿名用戶,依次點擊Security -> Users -> anonymous:
Docker學習筆記--CLI和Registry

使用私服

一樣,修改/etc/docker/daemon.json:

{
  "registry-mirrors": ["https://nexus.itrunner.org:8443"]
}

重啓docker後測試:

$ docker pull hello-world

從瀏覽器能夠方便的查看已下載的image:
Docker學習筆記--CLI和Registry

常見問題

docker error initializing network controller
刪除/var/lib/docker/network/files下的文件,從新啓動。

參考文檔

Docker Documentation
Product Manuals
Docker Glossary
Reference Documentation
Docker Samples
Docker中國
Best practices for writing Dockerfiles
How to Set Up a Registry Proxy Cache with Docker Open Source Registry
Jenkins與Docker的自動化CI/CD實戰

相關文章
相關標籤/搜索