Docker

Docker

本文将从 Docker 的基础概念出发,介绍容器、镜像、Dockerfile、数据卷、网络和 Docker Compose 的常见用法。通过实际示例,带你理解如何构建镜像、运行容器、挂载目录、暴露端口以及编排多服务应用,帮助开发者快速掌握 Docker 在本地开发、服务部署和环境隔离中的基本实践。

1.快速入门

推荐教程:https://docker.easydoc.net/doc/81170005/cCewZWoN/lTKfePfP

https://docs.docker.com/engine/reference/builder/

https://docs.docker.com/compose/compose-file/

1.1开始使用

  • 启动教程
docker run -dp 80:80 docker/getting-started
// -d 后台运行
// -p hostPort:containerPort 映射端口

1.2一个简单的应用例子

  1. 下载地址:https://github.com/docker/getting-started/archive/refs/heads/master.zip

  2. 解压其中的app文件夹

  3. 在app文件夹目录中创建Dockerfile

    FROM node:12-alpine
    RUN apk add --no-cache python2 g++ make
    WORKDIR /app
    COPY . .
    RUN yarn install --production
    CMD ["node","src/index"]
    EXPOSE 3000
    
  4. 构建docker镜像

    docker build -t getting-started . 
    # 镜像名:getting-started  
    # Dockerfile路径:.
    
  5. 启动容器

    docker run -dp 3000:3000 getting-started
    
  6. 改动容器内源码重新编译

  7. 查看正在所有容器

    docker ps
    
  8. 停止容器

    docker stop containerId
    
  9. 删除容器

    docker rm containerId
    

    强制删除正在运行容器:

    docker rm -f containerId
    
  10. 登录到docker

    docker login -u YOUR-USER-NAME.
    
  11. 使用tags创建相同镜像的不同名称

    docker tag getting-started YOUR-USER-NAME/getting-started
    
  12. 共享文件系统(挂载卷)

    docker volume create 卷名 # docker会自动创建命名卷,无需手动创建
    
    docker run -dp hostPort:containerPort -v 卷名:挂载路径(例:/etc/todo) 镜像名
    # docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
    

    查看共享文件系统位置:

    docker volume inspect 卷名
    
  13. 创建网络

    docker network create todo-app
    
  14. 启动数据库连接到网络

    powerShell:

    # 其中network选项相当于虚拟网卡名,network-alias相当于该局域网内此应用的域名
    docker run -d `
         --network todo-app --network-alias mysql `
         -v todo-mysql-data:/var/lib/mysql `
         -e MYSQL_ROOT_PASSWORD=secret `
         -e MYSQL_DATABASE=todos `
         mysql:5.7
    

    mysql 8.0以后需要执行以下命令:

    mysql -u root -p secret # 进入mysql
    alter user "root" identified with mysql_native_password by "secret";
    flush privileges;
    

    :docker会自动创建命名卷,无需手动创建

  15. 查看network-alias为mysql的ip地址

    docker run -it --network todo-app nicolaka/netshoot # 启动网络检查工具
    dig mysql
    
  16. 连接app到mysql

    PS> docker run -dp 3000:3000 `
       -w /app -v "$(pwd):/app" `
       --network todo-app `
       -e MYSQL_HOST=mysql `
       -e MYSQL_USER=root `
       -e MYSQL_PASSWORD=secret `
       -e MYSQL_DB=todos `
       node:12-alpine `
       sh -c "yarn install && yarn run dev"
    
  17. 使用docker-compose

    docker-compose version
    
    1. 创建docker-compose.yml

      version: "3.7"
      services:
      # 服务名将默认为network-alias(会自动创建网络)
        app:
          image: node:12-alpine
          command: sh -c "yarn install && yarn run dev"
          ports:
            - "3000:3000"
          working_dir: /app
          volumes:
            - ./:/app
          environment:
            MYSQL_HOST: mysql
            MYSQL_USER: root
            MYSQL_PASSWORD: secret
            MYSQL_DB: todos
      
        mysql:
          image: mysql
          volumes:
            - todo-mysql-data:/var/lib/mysql
          environment:
            MYSQL_ROOT_PASSWORD: secret
            MYSQL_DATABASE: todos
      
      volumes:
        todo-mysql-data:
      
    2. 启动应用

      docker-compose up -d
      
    3. 跟踪日志

      docker-compose logs -f app
      
    4. 停止应用

      docker-compose down
      docker-compose down --volumes # 删除卷
      
  18. 检查安装的文件版本是否有漏洞

    docker scan --login <image-name>
    
  19. 使用layer缓存

    1. 修改dockerfile
     # syntax=docker/dockerfile:1
     FROM node:12-alpine
     RUN apk add --no-cache python2 g++ make
     WORKDIR /app
     # 先安装依赖,如果没有变化,将会使用缓存
     COPY package.json yarn.lock ./
     RUN yarn install --production
     # 再复制其他文件
     COPY . .
     CMD ["node", "src/index.js"]
    
    1. 创建.dockerignore

      此文件会使docker在COPY时忽略这些文件

      node_modules
      

1.3开发环境映射本机文件到容器进行开发

PS> docker run -dp 3000:3000 `
     -w /app -v "$(pwd):/app" `
     node:12-alpine `
     sh -c "yarn install && yarn run dev"

1.4查看docker日志

docker logs -f <container-id>

2.Dockerfile

2.1简介

Dockerfile:用于构建应用的文件

.dockerignore:使用COPY命令时,忽略的文件夹

2.2构建

docker build -f /path/to/a/Dockerfile .  # 以指定Dockerfile构建
docker build -t shykes/myapp . # 以指定仓库名和tag构建

2.3Parser directives

用于控制docker编译器的参数,必须放置在Dockerfile的最前面

# directive=value
FROM ImageName
# unknowndirective=value
# knowndirective=value  此处将被视为注释

可用parser directives:

# 新版docker默认启动
# syntax=[remote image reference]

# syntax=docker/dockerfile:1
# syntax=docker.io/docker/dockerfile:1
# syntax=example.com/user/repo:tag@sha256:abcdef...

2.4escape

windows下推荐使用(指定自定义命令换行符,默认为\):

# escape=`

2.5ENV

注:该环境变量会写入镜像中,若不想写入,只想在构建阶段使用,推荐使用ARG

ENV abc=bye def=${abc} # 环境变量定义,通过${}引用

支持的命令:

ADD
COPY
ENV
EXPOSE
FROM
LABEL
STOPSIGNAL
USER
VOLUME
WORKDIR
ONBUILD

2.6FROM

语法:FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

[AS <name>]用法:在多个FROM之间COPY文件(COPY --from=<name>)

[--platform=<platform>]:linux/amd64,linux/arm64, `windows/amd64,$BUILDPLATFORM

FROM and ARG配合:

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app

FROM extras:${CODE_VERSION}
CMD  /code/run-extras

2.7RUN

用法:

RUN <command>  # command run in shell, /bin/sh -c on Linux or cmd /S /C on Windows
RUN ["executable", "param1", "param2"]

2.8CMD

CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)

与ENTRYPOINTS的区别:CMD可以被docker run的参数覆盖

2.9LABEL

镜像标签

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

查看标签:

docker image inspect --format='' myimage

2.10EXPOSE

只能当作文档提供给别人(docker run -P会暴露这些端口到随机的外部端口)

EXPOSE <port> [<port>/<protocol>...]  # 默认协议为TCP

实际暴露方法:

 docker run -p 80:80/tcp -p 80:80/udp ...

2.11ADD

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

ADD [--keep-git-dir=<boolean>] <git ref> <dir> # keep-git-dir表示.git是否包含

ADD --keep-git-dir=true https://github.com/moby/buildkit.git#v0.10.1 /buildkit
ADD git@git.example.com:foo/bar.git /bar

2.12COPY

COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

2.13WORKDIR

WORKDIR /a
WORKDIR b  # 相对于上一个路径
WORKDIR c
RUN pwd

2.14SHELL

切换当前shell

SHELL ["executable", "parameters"]

2.15Here-Document

# syntax=docker/dockerfile:1
FROM python:3.6
RUN <<EOT
#!/usr/bin/env python
print("hello world")
EOT

3.配置容器代理

启动容器时自动设置

~/.docker/config.json:

{
 "proxies":
 {
   "default":
   {
     "httpProxy": "http://192.168.1.12:3128",
     "httpsProxy": "http://192.168.1.12:3128",
     "noProxy": "*.test.example.com,.example2.com,127.0.0.0/8"
   }
 }
}