Featured image of post Docker入门最详细指北

Docker入门最详细指北

The Most Detailed Guide to Getting Started with Docker

Docker入门最详细指北

什么是 Docker

Docker是一个开源的平台,用于开发、交付和运行应用程序。它能够在WindowsmacOSLinux计算机上运行,并将某一应用程序及其依赖项打包至一个容器中,这些容器可以在任何支持Docker的环境中运行。容器彼此隔离,但可以通过特定的通道相互传递信息。

Docker提供了一个轻量级的虚拟化解决方案。由于运行在同一计算机上的所有容器共享同一个操作系统内核,避免了启动与维护虚拟机的开销。因此相比于传统的虚拟机,Docker容器更加轻便、快速、容易部署。使用Docker,开发者可以避免在两台计算机上运行效果不一致的问题,容器提供了一致的行为,进而使得应用程序在不同环境的计算机上有相同的运行效果。

Docker 架构

Docker不是虚拟机,本质上是对一个Linux内核上的进行隔离,把多个运行环境以容器的形式隔离开来。每个容器的环境都是独立的,但是所有容器共用一个Linux内核,这避免了虚拟机技术启动多个Linux内核所带来的开销。

img1.png

Docker 镜像

Docker镜像是容器的只读模板。每个镜像都包含了应用程序运行所需的操作系统、运行时、库、环境变量和应用代码等。镜像是静态的,用户可以根据镜像启动容器。

  • 镜像是构建容器的基础,每个容器实例化时都会使用镜像。

  • 镜像是只读的,不同容器使用同一个镜像时,容器中的文件系统层是独立的。

Docker 容器

Docker 容器是镜像的运行实例,是一个轻量级、可移植的执行环境。

  • 隔离性:每个容器都有自己的文件系统、网络和进程空间
  • 临时性:容器可以被创建、启动、停止、删除
  • 可写层:容器在镜像基础上添加了一个可写层
  • 进程级:容器内通常运行一个主进程

Docker 仓库

仓库是存储和分发镜像的地方,可以包含一个镜像的多个版本。

  • 公共仓库:如 Docker Hub,任何人都可以使用
  • 私有仓库:企业内部搭建,用于存储私有镜像
  • 官方仓库:由软件官方维护的镜像仓库

镜像、容器、仓库的关系

容器是由镜像制作出来的,而镜像可以从仓库获取,或者通过DockerFile构建。

类比理解:

  • 容器 = 糕点,镜像 = 制作糕点的模版,仓库 = 贩卖模具的摊贩

  • 如果镜像是类,那么容器就是对象实例。一个镜像可以创建多个容器,就像一个类可以创建多个对象。

img2.png

Docker网络

Bridge 桥接(默认)

img3.png

可以给容器分配不同的子网,每个子网之间的容器可以互相访问,并且通过DockerDNS服务,同一个子网的容器可以用类似http://<Contatiner Name>/的形式访问,即不用知道具体的IP

创建子网的命令如下

1
docker network create <NetworkName>

Host 模式

容器直接使用宿主机网络(即服务直接开放到宿主机的端口上,使用宿主机的IP地址)。

Docker的安装

Docker本质基于Linux内核,所以在其它操作系统上运行本质都是虚拟运行Linux。下面以Ubuntu做演示。

下载并运行Docker安装脚本。

1
2
curl -fsSL https://get.docker.com -o install-docker.sh
sudo sh install-docker.sh

脚本提示完成即安装好了Docker

Docker 常用命令

  1. pull命令(下载镜像)

    Example:

    1
    
    docker pull docker.io/library/nginx:latest
    

    可以看到docker.io/library/nginx:latest由三部分组成:

    • registry(仓库地址):docker.io代表官方仓库,官方仓库可以省略仓库地址

    • namespace(命名空间):library是官方仓库的命名空间,非官方的一般是上传者ID,官方仓库的命名空间可以省略。

    • tag(标签/版本):nginx:latestlatest可省去,也可指定版本。

    三者合起来docker.io/library/nginx写表示为镜像库。

    以上命令最后可简化为:

    1
    
    docker pull nginx
    

    注意:国内可能需要配置镜像站。

    1
    
    sudo nano /etc/docker/daemon.json
    

    输入:

    1
    2
    3
    4
    5
    6
    7
    
    {
        "registry-mirrors": [
            "https://docker.m.daocloud.io",
            "https://docker.1panel.live",
            "https://hub.rat.dev"
        ]
    }
    

    现在只有很少的国内镜像站存活,不保证镜像齐全。

    重启Docker

    1
    
    sudo service docker restart
    

    参数表

    --platform=XXX:表示拉取特定CPU架构的镜像(前提是存在这个架构的镜像)。

  2. imagesrmi命令(管理镜像)

    Example:

    1
    
    sudo docker images
    

    这个命令可以列出所有下载的Docker镜像。

    Example:

    1
    
    sudo docker rmi <ID/NAME>
    

    可以删除指定镜像,其中ID/NAME应当通过docker images查看。

  3. volume命令(创建挂载卷)

    Example:

    1
    
    sudo docker volume create nginx_html
    

    表示新建一个名为nginx_html的挂载卷。

    实际位置通过下面这个命令查询:

    1
    
    sudo docker volume inspect nginx_html
    

    注意:第一次使用的挂载卷的时候,Docker会把容器里面对应目录的文件复制一份到挂载卷进行初始化(详细见下文)。

    命令 作用
    docker volume list 列出所有的挂载卷
    docker volume rm <name> 删除指定挂载卷
    docker volume prune -a 删除所有没有任何容器使用的挂载卷
  4. run命令(使用镜像创建并运行容器)

    Example:

    1
    
    sudo docker run nginx <Custom Contatiner Name>
    

    其中nginx也可以换成镜像的ID<Custom Contatiner Name>为自定义容器名。

    如果没有pull镜像而使用run命令,那么会自动pull

    参数表

    参数 作用
    -d 分离模式,让容器在后台运行,避免卡住终端窗口。
    -p 格式为-p 255:80表示把的255端口数据转发到容器的80端口
    -v 绑定挂载:格式为-v 主机目录:容器内目录
    命名卷挂载:格式为-v 卷的名字:容器内目录
    这会把容器内目录实际反应到主机上,称作挂载卷。
    避免因为删除容器抹去该文件夹下面的数据,称作持久化保存。
    -e 向容器里面传递环境变量,具体的环境变量应该在容器的介绍页面查看。
    环境变量一般用于自定义容器内部服务的设置。
    -it 让当前终端进入容器进行交互,该命令一般同--rm一起使用。Ctrl+D退出。
    --rm 表示当容器停止的时候就把容器删除掉。
    --restart 格式--restart <always/unless-stopped>
    always会自动重启停止的容器
    unless-stopped会自动重启停止的容器,但手动停止的不会。
    --network 格式--network <NetworkName>,指定容器加入子网。

    实战Example:

    1
    
    sudo docker run -d -p 80:80 -v /website/html:/usr/share/nginx/html nginx
    

    注意:run每次都会创建并且运行一个容器,如果要对已经存在的容器进行启停,则需要使用docker start/stop <Contatiner Name/ID>

  5. create命令(创建容器)

    用法同上,具体区别是创建容器后不会启动,需要额外使用docker start

  6. exec命令(把Linux命令转到容器内)

    Example:

    1
    
    docker exec <Contatiner Name/ID> <linux命令>
    

    特别的,使用

    1
    
    docker exec <Contatiner Name/ID> /bin/sh 或 /bin/bash
    

    可以获得一个交互式的命令行环境,Ctrl+D退出。

    注意:为了压缩镜像大小,容器内部的系统一般都是极简的,许多常用工具需要自行安装。

  7. ps命令(查看进程状况)

    Example:

    1
    
    sudo docker ps <-a>
    

    这会列出运行容器的详细信息。

    存在-a则会列出全部容器。

    如果需要查询某个容器的全部信息,可以使用:

    1
    
    docker inspect <Contatiner ID>
    
  8. rm命令(删除容器)

    Example:

    1
    
    sudo docker rm <-f> <Contatiner Name>
    

    其中-f参数会强制删除运行中的容器。

  9. logs(查看容器日志)

    Example:

    1
    
    sudo docker logs <Contatiner Name/ID> <-f>
    

    其中-f表示实时日志。

Dockerfile

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#新的镜像必须基于一个现有的镜像构建,这个基础镜像可以是Linux系统或者其它的安装了某些组件的镜像
#第一句一般都是FROM
FROM python;3.13-slim

#切换到工作目录,类似cd 
WORKDIR /app

#把需要的文件复制到进去,这里的第一个.表示当前主机的当前目录
#这里的第一个.表示当前工作目录,也就是上面的WORKDIR /app所决定的目录
COPY . .

#表明需要执行的前置linux命令
RUN pip install -r requirements.txt

#声明镜像题库的服务端口
#仅仅只是对使用者的提示,实际使用的时候以-p参数为准
EXPOSE 8000

#每当容器启动的时候,容器会自动执行这个命令
#一个dockerfile只能写一个CMD
#CMD也可以写成ENTRYPOINT,优先级高一点
CMD ["python3","main.py"]

这里贴一个HydroOJ的评测机的Dockerfile做参考:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
FROM node:22

COPY ./entrypoint.sh /root/entrypoint.sh

RUN apt-get -qq update && \
    apt-get install -y \
    gcc \
    python3 \
    g++ \
    fp-compiler \
    openjdk-17-jdk-headless \
    php-cli \
    rustc \
    ghc \
    libjavascriptcoregtk-4.0-bin \
    golang \
    ruby \
    mono-runtime \
    mono-mcs && \
    chmod +x /root/entrypoint.sh && \
    # node is at /usr/local/bin but hydrojudge will find it at /usr/bin
    # so make a symlink to it
    ln -s /usr/local/bin/node /usr/bin/node

RUN yarn global add pm2 @hydrooj/hydrojudge && \
    wget https://github.com/criyle/go-judge/releases/download/v1.9.4/go-judge_1.9.4_linux_amd64v3 -O /usr/bin/sandbox && \
    chmod +x /usr/bin/sandbox

ENTRYPOINT ["/root/entrypoint.sh"]

构建镜像命令

1
docker build -t <name>:<version> .

其中.表示当前目录。

Docker Compose 技术

这是一个容器编排技术,可以方便的管理几个需要协同工作的容器,而不必使用繁琐的docker run命令。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
services:
    # 定义MongoDB服务,服务名:my_mongodb
    my_mongodb:
        # 使用官方MongoDB镜像(默认latest版本)
        image: mongo
        # 环境变量配置:初始化MongoDB根用户
        environment:
            # 设置MongoDB根用户名
            MONGO_INITDB_ROOT_USERNAME: name
            # 设置MongoDB根密码
            MONGO_INITDB_ROOT_PASSWORD: pass
        # 数据卷映射:宿主机目录 /my/datadir 挂载到容器内 /data/db(持久化MongoDB数据)
        volumes:
            - /my/datadir:/data/db

    # 定义Mongo-Express服务(MongoDB可视化工具),服务名:my_mongodb_express
    my_mongodb_express:
        # 使用官方Mongo-Express镜像(默认latest版本)
        image: mongo-express
        # 端口映射:宿主机8081端口映射到容器8081端口(访问可视化工具的入口)
        ports:
            - 8081:8081
        # 环境变量配置:Mongo-Express连接MongoDB的参数
        environment:
            # 指定要连接的MongoDB服务名(Docker Compose内网DNS可直接解析)
            ME_CONFIG_MONGODB_SERVER: my_mongodb
            # 连接MongoDB的管理员用户名(与上面MongoDB的根用户名一致)
            ME_CONFIG_MONGODB_ADMINUSERNAME: name
            # 连接MongoDB的管理员密码(与上面MongoDB的根密码一致)
            ME_CONFIG_MONGODB_ADMINPASSWORD: pass
        # 表示my_mongodb_express必须等my_mongodb正常工作了才会启动
        depends_on:
            - my_mongodb

这是一个Domjudgecompose文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
services:
  dj-mariadb:
    container_name: dj-mariadb
    image: mariadb:latest
    restart: unless-stopped
    ports:
      - "13306:3306"
    volumes:
      - ./database:/var/lib/mysql
    env_file: database.secret
    environment:
      - MYSQL_USER=domjudge
      - MYSQL_DATABASE=domjudge
      - CONTAINER_TIMEZONE=Asia/Shanghai
    command: --max-connections=1024 --max-allowed-packet=1G --innodb-snapshot-isolation=OFF --innodb-log-file-size=512M
    healthcheck:
      test: mysqladmin ping -h localhost -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
      start_period: 10s
      interval: 5s
      timeout: 1s
      retries: 5

  domserver:
    container_name: domserver
    image: domjudge/domserver:latest
    restart: unless-stopped
    ports:
      - "80:80"
    links:
      - 'dj-mariadb:mariadb'
    depends_on:
      dj-mariadb: { condition: service_healthy }
    env_file: database.secret
    environment:
      - MYSQL_HOST=mariadb
      - MYSQL_USER=domjudge
      - MYSQL_DATABASE=domjudge
      - CONTAINER_TIMEZONE=Asia/Shanghai

  judgehost:
    image: domjudge/judgehost:latest
    links:
      - 'domserver:domserver'
    depends_on:
      domserver: { condition: service_healthy }
    privileged: true
    volumes:
      - /sys/fs/cgroup/cpuset:/sys/fs/cgroup/cpuset:rw
      - /sys/fs/cgroup/memory:/sys/fs/cgroup/memory:rw
    env_file: judgehost.secret
    environment:
      - CONTAINER_TIMEZONE=Asia/Shanghai
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: dnsrr
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 5

Docker会给每个Compose文件中的容器自动新建一个子网,该文件中的所有容器会自动加入这个子网。

注意:文件名必须是docker-compose.yaml,如果不是,构建命令需要一个额外参数。

构建命令

1
docker compose up <-f filename.yaml> -d

停止并删除容器

1
docker compose down

停止容器

1
docker compose stop

启动容器

1
docker compose start

注意:以上命令都是对自动识别的docker-compose.yaml文件中的容器进行的操作。

本作品采用知识共享署名-非商业性使用-相同方式共享4.0国际许可协议进行许可(CC BY-NC-SA 4.0)
文章浏览量:Loading
Powered By MC ZBD Studio
发表了47篇文章 · 总计82.91k字
载入天数...载入时分秒...
总浏览量Loading | 访客总数Loading

主题 StackJimmy 设计
由ZephyrBD修改