命令行神器之 docker 篇

tldr docker

 tldr dockerManage Docker containers and images.- List currently running docker containers:    docker container ls- List all docker containers (running and stopped):    docker container ls -a- Start a container:    docker container start container- Stop a container:    docker container stop container- Start a container from an image and get a shell inside of it:    docker container run -it image bash- Run a command inside of an already running container:    docker container exec container command- Remove a stopped container:    docker container rm container- Fetch and follow the logs of a container:    docker container logs -f container

本文以实际操作为例,演示的docker的基本用法,操作示例如下:

  • ubuntu
  • mysql
  • hexo
  • portainer

ubuntu on docker

 docker pull ubuntu docker run --name ubuntu-1 -it ubuntu /bin/bash  root@c5bfcf6cf3ce:/# uname -aLinux c5bfcf6cf3ce 4.9.87-linuxkit-aufs #1 SMP Wed Mar 14 15:12:16 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux docker run --name ubuntu-2 -it ubuntu /bin/bash  root@0e2ad964e587:/# uname -aLinux 0e2ad964e587 4.9.87-linuxkit-aufs #1 SMP Wed Mar 14 15:12:16 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

docker image 与 docker container 的关系

 docker psCONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                    NAMES0e2ad964e587        ubuntu                "/bin/bash"              23 seconds ago      Up 23 seconds                                ubuntu-2c5bfcf6cf3ce        ubuntu                "/bin/bash"              41 seconds ago      Up 41 seconds                                ubuntu-1

从上面的docker ps结果可以看到,由同一个 IMAGE 通过docker run产生了2个独立的容器,一个容器内部文件修改不会影响另一个容器。IMAGE 和 CONTAINER 的关系,有点类似 Class 和其实例的关系,CONTAINER 只是 IMAGE 运行后的一个实例,可参考这篇关于AUFS的文章和Containers 101: Docker fundamentals这篇介绍 docker 基本原理的文章,从文章中各选了一张图作为示例说明如下。

docker image 和 docker container 图例说明

除了运行的容器这一层是可读写的,下面每一层(Layer)都是只读的,像运行 Dockerfile 中的每个RUN都会创建一个 IMAGE,IMAGE 下一层为其父 IMAGE,最下层无父 IMAGE 的称之为 BASE IMAGE。

在容器中增加新文件

退出当前的伪终端,同时退出容器。如果容器里有类似 MySQL 这样的服务在运行,退出伪终端并不会导致容器退出,如果需要停止此容器,需要运行docker container stop CONTAINER命令。

root@0e2ad964e587:/# echo test > ~/test.txtroot@0e2ad964e587:/# exit

docker container stop 关闭容器

 docker container stop ubuntu-2ubuntu-2

docker container start 启动容器

 docker container start ubuntu-2ubuntu-2

docker exec 进入正在运行的容器

 docker exec -it ubuntu-2 bashubuntu-2

查看前面新增文件的内容

使用docker container start CONTAINER可以恢复此容器上次退出时的最后状态。

root@0e2ad964e587:/# cat ~/test.txttestroot@0e2ad964e587:/#

mysql-5.7.22 on docker

mysql 数据存储目录创建

先在宿主机(host)上建立MySQL的数据存储目录,并会将此目录映射至 docker 容器中的/var/lib/mysql目录。

 mkdir -p /usr/local/var/mysql-5.7.22/

启动容器运行 mysql server

 docker run -p 3306:3306 --rm -v /usr/local/var/mysql-5.7.22:/var/lib/mysql \        -e MYSQL_ROOT_PASSWORD=test.root --name mysql-5.7.22 -d mysql:5.7.22 \        --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci \        --datadir=/var/lib/mysql --bind-address=0.0.0.0b6acb3be644d76f09eb10629bef370fc1fbd66ffbf11d4767e6bd497e4b07bc1

docker run 常用参数说明

-d, --detach           Run container in background and print container ID-e, --env list         Set environment variables-i, --interactive      Keep STDIN open even if not attached-p, --publish list     Publish a container's port(s) to the host (host-port:container-port)-t, --tty              Allocate a pseudo-TTY-v, --volume list      Bind mount a volume (host-dir:container-dir)    --name string      Assign a name to the container    --rm               Automatically remove the container when it exits

docker exec 进入运行中的容器

 docker exec -it mysql-5.7.22 bash

docker top 查看容器中的进程

 docker top mysql-5.7.22PID                 USER                TIME                COMMAND3861                999                 0:00                mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --datadir=/var/lib/mysql

docker container 操作容器

stop 停止容器

 docker container stop mysql-5.7.22

rm 删除容器

 docker container rm mysql-5.7.22

mysql docker-compose.yml 配置

version: '3.5'services:  mysql:    image: mysql:5.7.22    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --datadir=/var/lib/mysql    container_name: mysql-5.7.22    ports:      - "3306:3306"    restart: always    volumes:      - /usr/local/var/mysql-5.7.22:/var/lib/mysql    environment:      MYSQL_ROOT_PASSWORD: test.root
 docker container stop mysql-5.7.22mysql-5.7.22 docker container rm mysql-5.7.22mysql-5.7.22 docker-compose up -dCreating network "57_default" with the default driverCreating mysql-5.7.22 ... done docker psCONTAINER ID        IMAGE                        COMMAND                  CREATED              STATUS              PORTS                    NAMES2f62947ce66b        mysql:5.7.22                 "docker-entrypoint.s…"   About a minute ago   Up 8 seconds        0.0.0.0:3306->3306/tcp   mysql-5.7.22524f60344fb7        yuweijun/hexo-server:3.7.0   "docker-entrypoint.s…"   3 hours ago          Up 3 hours          0.0.0.0:4000->4000/tcp   hexo-server

hexo-3.7.0 on docker

docker pull 最新版本node

 docker pull node

安装hexo

 docker run --name node-10.5.0 -it node bash  root@ec3be3657e06:/# npm i -g hexo  root@ec3be3657e06:/# exit

docker commit 当前容器

docker commit会根据容器最后的状态制作一个新的 IMAGE。

 docker ps -aCONTAINER ID        IMAGE                 COMMAND                  CREATED              STATUS                      PORTS                    NAMESec3be3657e06        node                  "bash"                   About a minute ago   Exited (0) 31 seconds ago                            node-10.5.0
 docker commit node-10.5.0 yuweijun/hexosha256:92166c083a4f82e368c1067fe8cd9dc313b24636918ba0ccab7f58bd57fd63cc

docker image ls 查看当前 images

 docker image lsREPOSITORY             TAG                 IMAGE ID            CREATED              SIZEyuweijun/hexo          latest              92166c083a4f        About a minute ago   703MBnode                   latest              8753edeb1aa3        3 minutes ago        674MB

通过容器启动 hexo server

以下示例命令中hexo应用的根目录为/github.com/hexo

 docker run --name hexo-server -p 4000:4000 -v $HOME/.ssh:/root/.ssh \  -v /github.com/hexo:/github.com/hexo -it yuweijun/hexo \  hexo --cwd /github.com/hexo serverINFO  Start processingINFO  Hexo is running at http://localhost:4000/blog/. Press Ctrl+C to stop.

第一次运行之后生成了hexo-server容器,后面只要执行docker container start CONTAINER就可以启动hexo server

 docker container start hexo-serverhexo-server

docker container start -i

启动hexo-server容器可以运行hexo server,如果需要控制台输出日志,命令需要多传一个参数:

-i --interactive Attach container’s STDIN

 docker container start -i hexo-serverINFO  Start processingINFO  Hexo is running at http://localhost:4000/blog/. Press Ctrl+C to stop.
 docker container lsCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES1d46ae36a29a        yuweijun/hexo       "hexo --cwd /github.…"   14 minutes ago      Up 6 minutes        0.0.0.0:4000->4000/tcp   hexo-server0e2ad964e587        ubuntu              "/bin/bash"              6 hours ago         Up 5 hours                                   ubuntu-2c5bfcf6cf3ce        ubuntu              "/bin/bash"              6 hours ago         Up 6 hours                                   ubuntu-1b6acb3be644d        mysql:5.7.22        "docker-entrypoint.s…"   17 hours ago        Up 17 hours         0.0.0.0:3306->3306/tcp   mysql-5.7.22

docker logs -f 查看容器运行日志

 docker logs -f hexo-serverINFO  Start processingINFO  Hexo is running at http://localhost:4000/blog/. Press Ctrl+C to stop.

通过容器执行 hexo clean

 docker run --rm --name hexo-clean \  -v $HOME/.ssh:/root/.ssh -v /github.com/hexo:/github.com/hexo \  -it yuweijun/hexo hexo --cwd /github.com/hexo cleanINFO  Deleted database.before exist

第一次运行之后生成了hexo-clean容器,后面只要执行docker container start -i CONTAINER就可以。

 docker container start -i hexo-cleanINFO  Deleted database.before exist

Dockerfile 文件配置

docker run只接受一个命令,如果需要执行一系列命令时,最好是使用 Dockerfile 定制自己的镜像文件。

docker 启动脚本 docker-entrypoint.sh

#!/bin/shif [ -e /github.com/hexo ]; then    cd /github.com/hexo    if [ ! -e /github.com/hexo/node_modules ]; then        npm install    fi    hexo clean    hexo serverelse    echo 'docker run --name hexo-server -p 4000:4000 -v $HOME/.ssh:/root/.ssh -v /github.com/hexo:/github.com/hexo -it yuweijun/hexo-server:3.7.0'fi

Dockerfile

FROM yuweijun/hexoCOPY docker-entrypoint.sh /usr/local/bin/ENTRYPOINT ["docker-entrypoint.sh"]EXPOSE 4000CMD ["/bin/bash"]

docker-entrypoint.sh文件和Dockerfile文件放在同一个目录下,并且控制台cd到这个目录下执行以下镜像构建命令:

docker build 构建

 docker build -t yuweijun/hexo-server:3.7.0 .Sending build context to Docker daemon  3.072kBStep 1/5 : FROM yuweijun/hexo ---> ef20fe8ae205Step 2/5 : COPY docker-entrypoint.sh /usr/local/bin/ ---> Using cache ---> cab9386a8e74Step 3/5 : ENTRYPOINT ["docker-entrypoint.sh"] ---> Using cache ---> e05e55eb54b1Step 4/5 : EXPOSE 4000 ---> Using cache ---> d2517e6fc536Step 5/5 : CMD ["/bin/bash"] ---> Using cache ---> 8dc78ad81ca3Successfully built 8dc78ad81ca3Successfully tagged yuweijun/hexo-server:3.7.0

Dockerfile RUN/ENTRYPOINT/CMD 区别

Dockerfile文件中的RUNCMDENTRYPOINT这三个指令看上去功能很类似,都可以用来运行命令,下面简单说一下三者区别:

  1. RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
  2. CMD 设置容器启动后默认执行的命令及其参数,如果有多个 CMD,则只有最后一个生效,但 CMD 能够被docker run后面跟的命令行参数替换。
  3. ENTRYPOINT 配置容器启动时运行的命令,ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行,与 CMD 不同的是,ENTRYPOINT 一定会被执行。
  4. 如果 Docker 镜像的用途是运行应用程序或服务,比如运行一个 MySQL,应该优先使用 Exec 格式的 ENTRYPOINT 指令。

启动新版 hexo-server

先删除前面生成的hexo-server容器。

 docker container rm hexo-server

启动新版hexo-server

 docker run --name hexo-server -p 4000:4000 \  -v $HOME/.ssh:/root/.ssh -v /github.com/hexo:/github.com/hexo \  -it yuweijun/hexo-server:3.7.0INFO  Deleted database.INFO  Start processingINFO  Hexo is running at http://localhost:4000/blog/. Press Ctrl+C to stop.

hexo docker-compose.yml 配置

version: '3.5'services:  hexo:    image: yuweijun/hexo-server:3.7.0    container_name: hexo-server    ports:      - "4000:4000"    restart: always    volumes:      - $HOME/.ssh:/root/.ssh      - /github.com/hexo:/github.com/hexo

使用docker-compose命令启动hexo-server服务:

 docker container rm hexo-server docker-compose up -dRecreating c5e37b50081e_370_hexo_1 ... done docker container lsCONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                    NAMES524f60344fb7        yuweijun/hexo-server:3.7.0   "docker-entrypoint.s…"   2 minutes ago       Up 11 seconds       0.0.0.0:4000->4000/tcp   hexo-server

portainer on docker

portainer(基于 Go)是一个轻量级的 docker 管理工具。

 docker volume create portainer_dataportainer_data docker run -d -p 9000:9000 --name portainer \  --restart always -v /var/run/docker.sock:/var/run/docker.sock \  -v portainer_data:/data portainer/portainerUnable to find image 'portainer/portainer:latest' locallylatest: Pulling from portainer/portainerd1e017099d17: Pull completea8d2fd955b4d: Pull completeDigest: sha256:7affc7f6d02ebceaa4e0cd137ef3c784629e5ebfa2354c4776337f8bc42664a4Status: Downloaded newer image for portainer/portainer:latest699ab479af8316ac88c1dbdb1990f84d3b76a1f6deb3e35ad8f3a05b757d5080

one service per container

容器的主要是通过 Dockerfile 配置中最后的 ENTRYPOINT 和 CMD 运行进程,通常建议通过每个容器使用一项服务来分隔关注点。

Containers vs VMs

二者区别简单来说就是,docker 的 IMAGE 或者 CONTAINER 没有 OS 内核,与宿主机共享内核。

docker commands diagram

References

  1. get started - docker
  2. Run multiple services in a containe
  3. docker cheat sheet
  4. Docker RUN vs CMD vs ENTRYPOINT
  5. How to Automate Docker Deployments
  6. docker commit
  7. docker exec
  8. docker run
  9. docker container start
  10. portainer Deployment
  11. docker compose version 3 reference
  12. Containers 101: Docker fundamentals
  13. What is Docker and How to Use it With Python
  14. Docker Getting Start: Related Knowledge
  15. Understanding Volumes in Docker