Docker

为什么用Docker

一种新兴的虚拟化方式。
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而Docker容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。
Docker 对系统资源的利用率更高,不需要进行硬件虚拟以及运行完整操作系统等额外开销
Docker 容器应用直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间
Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性
Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署
Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的,可以更轻松的迁移

一些概念:

  1. 镜像(Image):可以将镜像视为软件打包的模板。
    1. 功能:镜像是一个只读的文件,其中包含了运行应用程序所需的一切,包括代码、运行时环境、依赖项和配置。
  1. 容器(Container):容器是基于镜像创建的一个运行实例。
    1. 工能:可以将容器视为镜像的运行时进程,它是一个隔离的环境,其中可以运行应用程序和服务。
    2. 特性:每个容器都具有自己的文件系统、网络和进程空间,可以独立运行应用程序。
    3. 📌
      镜像和容器关系的例子: 1. 莎士比亚心中的哈姆雷特就像是一个镜像,观众在看了这个戏剧之后,在自己心中就有了一个哈姆雷特,观众心中的哈姆雷特就是容器。 2. Python 中类和实例的关系,类是一个模板,实例是类的具体实现。
  1. 仓库(Repository):仓库是用于存储和组织镜像的地方。Docker Registry服务器专门用来存放仓库一个 Docker Registry 中可以包含多个 仓库;每个仓库可以包含多个 标签;每个标签对应一个镜像。
    1. 通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
notion imagenotion image

Docker安装

Linux安装教程(官方文档):https://docs.docker.com/engine/install/ubuntu/

版本选择

Docker Desktop 和 Docker Engine怎么选:
  • 在有图形界面的系统中(Windows 或 macOS等),推荐使用:Docker Desktop;它集成 Docker Engine、Docker CLI、Docker Compose、Kubernetes(可选),以及一个图形化界面,适合 Windows 和 macOS 用户。
  • 在没有图形界面的系统中(Linux),推荐使用:Docker Engine
    • Docker CE(Community Edition,社区版):开源免费
    • Docker EE(Enterprise Edition,企业版,现已并入 Mirantis):商业付费

仓库安装(Ubuntu)

卸载旧的可能有冲突的包

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
存储在 /var/lib/docker/ 中的映像、容器、卷和网络不会自动删除。如果您想从全新安装开始,并希望清理任何现有数据
如果希望彻底卸载Docker Engine重新开始安装,则可以执行
# 卸载 Docker Engine、CLI、containerd 和 Docker Compose 软件包: sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras # 手动删除任何已编辑的配置文件 sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd

仓库配置

# 更新软件包列表 sudo apt-get update # 安装必要的证书和工具:ca-certificates:提供系统用来验证 SSL 证书的证书;curl:用于从网络上下载文件的工具。 sudo apt-get install ca-certificates curl # 创建目录以存储 GPG 密钥,-m 0755 设置目录权限,以便所有用户可以读取和进入该目录,但只有目录所有者可以修改。 sudo install -m 0755 -d /etc/apt/keyrings # 下载 Docker 的官方 GPG 密钥 sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc # -fsSL 参数的含义: # -f:在下载过程中遇到错误时,curl 会失败。 # -s:以静默模式运行,避免输出进度信息。 # -S:即使在静默模式下,也显示错误信息。 # -L:如果遇到重定向,则跟随重定向。 # 设置密钥的权限,a+r 表示所有用户都可以读取 sudo chmod a+r /etc/apt/keyrings/docker.asc # 添加 Docker 存储库到 APT 源 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # $(dpkg --print-architecture):获取当前系统的架构(如 amd64)。 # $(. /etc/os-release && echo "$VERSION_CODENAME"):获取当前 Ubuntu 版本的代号(如 jammy)。 # signed-by=/etc/apt/keyrings/docker.asc:指定用于验证存储库签名的 GPG 密钥路径。 # 将生成的内容通过 echo 输出并通过 tee 命令写入到 /etc/apt/sources.list.d/docker.list 文件中。> /dev/null 确保 tee 命令的输出不会显示在终端上。 # 更新软件包列表 sudo apt-get update

安装Docker

# 直接安装最新版本 sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 列出所有可用版本 apt-cache madison docker-ce | awk '{ print $3 }' # 设置版本进行安装 VERSION_STRING=5:20.10.24~3-0~ubuntu-jammy sudo apt-get install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-buildx-plugin docker-compose-plugin

验证Docker

sudo docker run hello-world

安装包安装

实操查找版本

以Ubuntu系统为例:
  1. 进入:https://download.docker.com/linux/ubuntu/ 这个网址,包含目录如下:
      • dists/
        • 这是 Docker APT 存储库的核心目录,包含了不同的 Ubuntu 版本和架构的文件包。
        • 进入 dists/ 目录后,你会看到各个 Ubuntu 发行版的名称,如 bionic/(Ubuntu 18.04)、focal/(Ubuntu 20.04)、jammy/(Ubuntu 22.04)等。
        • 进一步进入每个发行版的目录,可以看到 stable/test/ 等子目录,这些目录中包含了对应版本的 Docker Engine 及其相关组件的安装包。
      • gpg 
        • 包含 Docker APT 仓库的 GPG 密钥,用于验证从这个仓库下载的软件包的真实性和完整性。安装 Docker 时,通常需要添加这个 GPG 密钥到系统中。
  1. 进入对应的系统(我的是jammy/(Ubuntu 22.04)),进入:https://download.docker.com/linux/ubuntu/dists/jammy/ 之后,目录包含如下
      • stable/test/nightly/:
        • 这些是 Docker 的不同发布渠道(release channel)。每个目录中包含不同类型的 Docker 软件包。
          • stable/:包含稳定版本的 Docker 软件包,适合生产环境使用。
          • test/:包含测试版的 Docker 软件包,用于开发者在发布正式版本之前测试新功能。
          • nightly/:包含每日构建版本,提供最新的功能和更新,但可能不稳定,仅用于实验和测试。
        • 通常,建议使用 stable/ 版本,因为它是经过充分测试和验证的。
      • ReleaseInReleaseRelease.gpg:
        • Release:描述该发行版中可用软件包的元数据文件,包含每个软件包的版本信息、依赖关系等。
        • InRelease:包含了 Release 文件的内容以及其 GPG 签名,提供了一种验证文件完整性和真实性的方式。
        • Release.gpg:是对 Release 文件的独立 GPG 签名,用于确认文件的完整性和来源。
      • pool/
        • 该目录包含了所有 Docker 包文件的实际存放位置,按软件包的名称进行组织。
        • 包括 docker-ce(Docker 社区版)、containerd.io(容器运行时)等。
        • 这些 .deb 文件可以直接下载,用于在没有网络连接的情况下进行离线安装。
  1. 进入pool/目录,选择稳定版stable/, 然后选择系统架构类型
      • amd64/:用于 64 位架构的包文件(也称为 x86_64 架构)。
      • arm64/:用于 ARM 架构的包文件。
      • s390x/:用于 IBM 系统 z 架构的包文件。
  1. 我Ubuntu是安装在Mac M1电脑上的,所以选择arm64/架构,进去之后包含以下类型文件:
      • containerd.io(必须):容器运行时,这是 Docker 引擎所依赖的组件。
      • docker-ce(必须):Docker 社区版的核心包,即 Docker 引擎。
      • docker-ce-cli(必须):Docker 命令行工具。
      • docker-compose-plugin(可选-推荐) ::用于多容器管理的插件。
      • docker-buildx-plugin (可选-推荐):用于多平台构建的插件。
      • docker-ce-rootless-extras (可选):用于支持 无特权(rootless)模式 的 Docker 运行。

选择合适的版本

  • 推荐版本:20.10…
  • 兼容性:选择与其他软件包兼容的版本。例如,docker-cedocker-ce-cli 和 containerd.io 通常需要保持版本兼容。如果选择 docker-ce 的最新版本,也要选择与之匹配的 docker-ce-cli 和 containerd.io 版本。

开始安装(Ubuntu)

下载必需的 .deb 包
# 创建一个目录来存放下载的包 mkdir -p ~/docker_install && cd ~/docker_install # 下载 Docker CE、CLI、containerd 和 Docker Compose 插件(根据需要) wget https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/docker-ce_<version>_amd64.deb wget https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/docker-ce-cli_<version>_amd64.deb wget https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/containerd.io_<version>_amd64.deb wget https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/docker-buildx-plugin_<version>_amd64.deb wget https://download.docker.com/linux/ubuntu/dists/focal/pool/stable/amd64/docker-compose-plugin_<version>_amd64.deb # 注意: 请将 <version> 替换为要下载的具体版本号。您可以在 Docker 官方下载页面上找到这些版本,并替换相应的链接。
安装依赖包:将所有下载的 .deb 文件一起安装,以确保正确处理包的依赖关系:
sudo dpkg -i *.deb # 或者执行: sudo dpkg -i ./containerd.io_<version>_<arch>.deb \ ./docker-ce_<version>_<arch>.deb \ ./docker-ce-cli_<version>_<arch>.deb \ ./docker-buildx-plugin_<version>_<arch>.deb \ ./docker-compose-plugin_<version>_<arch>.deb
如果在安装过程中遇到依赖问题,可以使用以下命令来解决:
sudo apt-get install -f
然后重新运行 dpkg 命令:
sudo dpkg -i *.deb
启动 Docker 并验证安装
sudo service docker start docker --version sudo docker run hello-world
sudo systemctl start docker sudo systemctl status docker sudo systemctl enable docker

遇到问题(Ubuntu)

  1. 运行测试镜像:sudo docker run hello-world
  1. 报错:
    1. Unable to find image 'hello-world:latest' locally docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers). See 'docker run --help'.
  1. 原因:网络不能访问docker 的镜像源
  1. 方案1:配置国内镜像源
      • 更改或新增配置文件:vim /etc/docker/daemon.json
        • { "registry-mirrors": [ "https://docker.mirrors.ustc.edu.cn", "https://registry.docker-cn.com", "https://hub-mirror.c.163.com", "https://mirror.iscas.ac.cn" ] }
      • 重启服务:service docker restart
      • 检查镜像源:docker info|grep Mirrors -A 5 ——匹配到 "Mirrors" 的行后,再额外显示匹配行后面的 5 行内容(-A 表示 "After")
  1. 方案2:去阿里云官方申请了镜像地址也加速失败
  1. 结果:更新完之后发现还是不行,网上一搜才知道是很多镜像源已经停止服务了(放弃)

开始安装(CentOS 7.9)

这里下载的最新版的 docker 安装包,如果只下载几个会提示依赖问题
sudo yum localinstall containerd.io-1.6.33-3.1.el7.x86_64.rpm docker-ce-26.1.4-1.el7.x86_64.rpm docker-ce-cli-26.1.4-1.el7.x86_64.rpm docker-buildx-plugin-0.14.1-1.el7.x86_64.rpm docker-compose-plugin-2.27.1-1.el7.x86_64.rpm -y
以上安装遇到 GPG 验证问题
  • 导入 gpg 密钥:sudo rpm --import gpg
  • 验证 gpg 密钥:rpm -qa gpg-pubkey*
  • 重新执行安装命令即可安装成功

启动设置

# 单次启动 sudo systemctl start docker # 重载配置文件 sudo systemctl daemon-reload # 重启docker(二选一) sudo systemctl restart docker service docker restart # 设置开机启动docker sudo systemctl enable docker # 查看docker状态 sudo systemctl status docker

快速制作Python环境镜像

详细镜像制作过程见下文【镜像制作】

1、创建 Dockerfile 文件

# 选择基础镜像 FROM python:3.9 # 设置工作目录 WORKDIR /app # 复制 requirements.txt 文件到容器中的工作目录(否则在构建镜像时会报找不到requirements.txt文件的错) COPY requirements.txt . # 安装所需的 Python 包 RUN pip install --no-cache-dir -r requirements.txt # 文件安装(如果使用文件安装则必须使用COPY指令复制文件到容器中) # RUN pip install --no-cache-dir flask # 单独安装

2、构建镜像

docker build -f Dockerfile -t test_image . # -f:使用指定文件来构建,不写-f则默认使用Dockerfile文件 # -t:指定镜像的名称为 test_image。 # .:表示上下文路径,即 Dockerfile 所在目录。

3、导出与导入

# 1. 使用 save 命令导出镜像为 tar 文件 docker save -o my-image.tar my-image # 将 my-image 镜像导出为 my-image.tar 文件,保存到当前路径下 # 2. 将 tar 文件传输到新机器上 # 3. 使用 load 命令加载镜像 docker load -i my-image.tar # 在新机器上拿到 tar 文件后,使用 load 命令加载镜像

4、从镜像创建容器

docker images # 查看镜像列表 # 创建容器:-d:后台运行;--name:指定容器名称;-v:设置挂载路径;-it:以交互模式进入;/bin/bash:在容器内提供一个交互式的终端环境 # -it test_image /bin/bash 与 exec 命令中的相同,但不可省略 docker run -d --name test_container -v /home/anjhon/project/python_app_docker:/app/python_app_docker -it test_image /bin/bash # 进入容器;-it:以交互模式进入;/bin/bash:在容器内提供一个交互式的终端环境 docker exec -it test_image /bin/bash # 退出容器 exit

Python 镜像对比

版本名称
版本示例
版本大小
版本特点
适用场景
标准版
python:3.9
~900MB
基于 Debian Buster,包含完整的 Python 环境和常用工具(如 pipsetuptools),功能最全。
开发环境、测试环境,需要完整工具链的场景。
Slim 版
python:3.9-slim
~120MB
基于 Debian Buster,仅包含 Python 运行所需的最小依赖,去除了非必要工具和文档,体积小。
生产环境,对镜像大小敏感的场景。
Alpine 版
python:3.9-alpine
~50MB
基于 Alpine Linux,体积最小,但可能存在兼容性问题(如缺少 glibc)。
对镜像大小极度敏感的场景,且能接受潜在的兼容性调整。
Buster 版
python:3.9-buster
~900MB
基于 Debian Buster,包含完整的系统工具链,适合需要兼容 Debian 的场景。
需要与 Debian 系统兼容的开发或生产环境。
Bullseye 版
python:3.9-bullseye
~900MB
基于 Debian Bullseye,较新的 Debian 版本,包含更新的系统工具链。
需要较新 Debian 系统支持的场景。
Windowsservercore
python:3.9-windowsservercore
~4GB
基于 Windows Server Core,适用于 Windows 容器环境。
需要在 Windows 容器中运行 Python 的场景。
Nano Server
python:3.9-nanoserver
~1GB
基于 Windows Nano Server,体积较小,适用于轻量级 Windows 容器环境。
需要在轻量级 Windows 容器中运行 Python 的场景。

镜像操作

docker search python # 搜索镜像(如果配置了镜像源,那么就是在镜像源内搜索) # 也可以去官方找:https://hub.docker.com/_/python/tags docker pull (镜像ID | 镜像名[:标签]) # 拉取镜像(不指定标签则拉取最新版本的) docker pull python:3.9-alpine3.20 # 拉取指定版本的镜像 docker push my-image:latest # 将本地镜像上传到 Docker 仓库 docker inspect my-image # 查看镜像的详细信息,包括配置和层信息 # 查看镜像列表(以下两个命令功能相同): 结果包含了仓库名、标签、镜像ID、创建时间以及所占用的空间(这里显示的是解压后的大小,Docker Hub 中显示的是压缩体积) docker images docker image ls # Docker 1.13 及以后的版本中引入的更具可读性的命令格式 # REPOSITORY TAG IMAGE ID CREATED SIZE # hello-world latest ee301c921b8a 7 months ago 9.14kB docker image ls 可选参数: # -a(--all):列出所有镜像,包括中间层镜像;如:docker image ls -a # -q(--quiet):只显示镜像的 ID;如:docker image ls -q # -f (--filter):根据条件过滤输出的镜像;如:docker image ls -f dangling=true; docker image ls --filter "dangling=true"(只显示悬空镜像) # --format:自定义输出格式;如:docker image ls --format "{{.Repository}}: {{.Tag}}"(以指定格式输出镜像信息) # --no-trunc:不截断输出的镜像 ID 和其他信息;如:docker image ls --no-trunc # --digests:显示镜像的摘要信息;如:docker image ls --digests # --help:显示帮助信息;如:docker image ls --help docker image ls ubuntu # 根据仓库名列出不同标签的镜像 docker image ls ubuntu:18.04 # 指定仓库名和标签查看镜像 docker image ls -f since=mongo:3.2 # 根据条件筛选镜像,列出 mongo:3.2 以后的版本 docker image ls -f before=mongo:3.2 # 根据条件筛选镜像,列出 mongo:3.2 之前的版本 # 悬空镜像(Dangling Images)是指那些没有任何标签(tag)或没有被任何容器使用的 Docker 镜像。这些镜像通常是由于镜像的更新或构建过程中的中间层而产生的;虽然它们不再被使用,但仍然占用磁盘空间,可能导致存储资源的浪费。 docker image ls -f dangling=true # 只显示悬空镜像 docker image prune # 清除悬空镜像 # 查看 Docker 系统的磁盘使用情况,包括镜像、容器、数据卷所占用的空间,返回类型、数量、大小、百分比等 docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 24 0 1.992GB 1.992GB (100%) Containers 1 0 62.82MB 62.82MB (100%) Local Volumes 9 0 652.2MB 652.2MB (100%) Build Cache 0B 0B # 删除镜像 docker rmi [选项] <镜像1> [<镜像2> ...] docker image rm [选项] <镜像1> [<镜像2> ...] # <镜像> 可以是镜像短 ID、镜像长 ID、镜像名或者镜像摘要(默认列出的是短 ID) # 有些删除操作可能有 Untagged 提示,说明是取消了镜像的标签,因为除了当前要删除的标签,可能还有其他标签指向这个镜像;也可能某个其他镜像正依赖于当前镜像的某一层;或者有用这个镜像启动的容器存在(即使容器没有运行) # 所以并非所有的 docker image rm 都会真正删除镜像,有可能仅仅是取消某个标签 docker image rm <镜像>@<镜像摘要> # 根据镜像摘要删除 docker image rm $(docker image ls -q redis) # 根据条件查询删除 docker image rm $(docker image ls -q -f before=mongo:3.2) # 根据条件查询删除 docker image rm 可选参数: # -f, --force:强制删除镜像,即使该镜像被一个或多个容器使用;如:docker image rm -f my-image # -no-prune:在删除镜像时不删除其父镜像;如:docker image rm --no-prune my-image # --help:显示帮助信息;如:docker image rm --help # 查看镜像历史 docker history nginx:v2

容器操作

创建容器

一个镜像可以用来创建多个容器,每个容器都是镜像的一个独立运行实例。
使用 docker run 创建并启动一个新容器时,所有指定的参数(如端口映射、卷挂载、环境变量等)都会被保存到该容器的配置中。在之后在使用 docker start 命令启动已经创建的容器时,不需要再次指定
docker run --help docker run (镜像ID | 镜像名[:标签]) # 从镜像创建一个容器, docker run -d -p 88:80 -v /app/nghtml:/user/shar/nginx/html --name app1 -- restart always nginx docker run 可选参数: # -d(--detach):后台运行;如:docker run -d my-image # -p(--publish) :将容器的端口映射到主机的端口;如:docker run -p 8080:80 my-image(将容器的 80 端口映射到主机的 8080 端口) # --name:为容器指定一个名称;如:docker run --name my-container my-image # -e(--env):设置环境变量;如:docker run -e MY_ENV_VAR=value my-image # -v(--volume):将主机目录或文件挂载到容器中;如:docker run -v /host/path:/container/path my-image 第一个是服务器主机目录,第二个是容器目录;挂载之后服务就会以服务器目录为准,如果其中没有内容就会报错,需要将内容迁移到挂载目录。 # --restart:设置容器的重启策略;如:docker run --restart unless-stopped my-image # --restart no:默认值。容器退出时不会自动重启。 # --restart always:无论容器是正常退出还是异常退出,都会自动重启容器。 # --restart unless-stopped:容器会在异常退出时自动重启,但如果容器被手动停止(使用 docker stop),则不会重启。 # --restart on-failure:仅在容器非零退出状态时重启容器。可以指定一个可选的最大重启次数;--restart on-failure:5(最多重启 5 次) # --rm:在容器停止后自动删除容器;如:docker run --rm my-image; # --network:指定容器连接的网络;如:docker run --network my-network my-image # -it:以交互模式运行容器,并分配一个伪终端;如:docker run -it my-image /bin/bash # --memory:设置容器的内存限制(默认使用主机系统的所有可用内存);如:docker run --memory 512m my-image
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
  • 检查本地是否存在指定的镜像,不存在就从 registry 下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
  • 从地址池配置一个 ip 地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被终止
📌
运行镜像生成容器后,通常有两种方式来操作容器内的内容:
  • 容器开放一个访问端口,从浏览器访问
  • 在容器内打开一个 bash shll,进行命令行操作

容器状态与启停

docker ps # 查看运行中的容器 docker ps 可选参数: # -a, --all:列出所有容器,包括已停止的容器;如:docker ps -a # -q, --quiet:只显示容器的 ID;如:docker ps -q # -f, --filter:根据条件过滤输出的容器;如:docker ps --filter "status=exited"(只显示已退出的容器) # --format:自定义输出格式;如:docker ps --format "{{.ID}}: {{.Names}}"(以指定格式输出容器信息) # --no-trunc:不截断输出的容器 ID 和其他信息;如:docker ps --no-trunc # -n, --last:显示最近创建的 N 个容器;如:docker ps -n 5(显示最近的 5 个容器) # --size:显示容器的大小;如:docker ps --size # --help:显示帮助信息;如:docker ps --help docker stop <container_id|container_name> docker start <container_id|container_name> docker restart <container_id|container_name> docker stats <container_id|container_name> # 显示容器的实时资源使用情况 docker logs <container_id|container_name> # 查看容器日志 docker rm <container_id|container_name> # 删除容器,需要先停止容器 docker rm -f <container_id|container_name> # 删除容器,运行中的也能删除 docker rm -f $(docker ps -aq) # 删除所有容器;docker ps -aq 会返回所有容器的 ID 列表;$(...) 替换语法 docker logs <container_id|container_name> # 查看容器的日志输出 docker inspect <container_id|container_name> # 查看容器的详细信息 docker top <container_id|container_name> # 显示容器内正在运行的进程 docker cp <container_id|container_name>:/path/in/container /path/on/host # 在主机和容器之间复制文件或目录 docker exec -it <container_id|container_name> /bin/bash # 进入容器;-it:以交互模式进入;/bin/bash:在容器内提供一个交互式的终端环境 exit # 退出容器,回到服务器 docker commit <container_id|container_name> <image_name[:tag]> # 将容器的当前状态保存为一个新的镜像 docker commit 可选参数: # -m, --message:为提交添加说明;如:docker commit -m "Update app" my-container my-new-image # -a, --author:指定作者信息;如:docker commit -a "Author Name" my-container my-new-image # -p, --pause:在提交时暂停容器;如:docker commit -p my-container my-new-image(默认值为 true,表示在提交时暂停容器) # --change:应用 Dockerfile 指令的变化;如:docker commit --change "ENV MY_ENV_VAR=value" my-container my-new-image # --help:显示帮助信息;如:docker commit --help docker commit -m "更新了一些东西" mynginx mynginx:v1.0 # 将容器打包成镜像(会自动生成镜像ID) docker commit -m "Added python setuptool pip numpy" -a "wangxiaolei" 0c28c802c5e6 mycentos:mydev

打包传输

文件形式

docker save -o filename.tar <image_id|image_name[:tag]> # 将镜像保存成文件(一般是tar文件) docker save -o mynginx.tar mynginx:v1.0 # 将镜像保存成文件(最终生成mynginx.tar文件) # 文件传输之后 docker load -i mynginx.tar # 加载文件为镜像

线上形式

docker login # 登陆docker-hub(输入账号密码) docker tag mynginx:v1.0 anjhon/mynginx:v1.0 # 创建一个新名称的镜像(docker-hub上要求镜像名是用户名+镜像名)这个镜像是应用了原来的镜像的 docker push anjhon/mynginx:v1.0 # 推送镜像到docker-hub

Docker存储

数据存储在容器内部:
  • 修改数据需要先进入容器内部,操作繁琐
  • 容器崩溃后数据丢失
一般用来操作存储配置文件和数据

目录挂载

docker run -d -p 80:80 -v /app/nghtml:/user/shar/nginx/html --name app1 nginx # -v:目录挂载(挂载就像外接U盘);第一个是服务器目录,第二个是容器目录;挂载之后服务就会以服务器目录为准,如果其中没有内容就会报错,需要将内容迁移到挂载目录

卷映射

卷映射其实也是一种挂载,只是在挂载的时候自动将 容器内需要挂载的文件夹中的内容 同步到服务器上的卷中。
docker run -d -p 88:80 -v /app/nghtml:/user/shar/nginx/html -v ngconfig:/etc/nginx --name app2 nginx # 第一个-v是挂载目录,他需要提供 ——> 服务器路径:容器路径 # 第二个-v是卷映射,它需要提供 ——> 卷名:容器路径 # 这个命令会在服务器的:/var/lib/docker/volumes/ 文件夹中生成一个同名的卷,其中有一个_data文件夹包含了容器文件夹中的内容,在这里修改文件内容,容器内部也会发生变化 docker volume ls # 查看所有的卷 docker volume inspect 卷名 # 查看卷的详情(包含卷的位置)
只有在首次使用卷映射时,如果卷为空且容器目录中有数据,Docker 才会将容器目录中的数据复制到卷中。之后,卷中的数据就是独立存在的,挂载到任何容器都不会被初始目录覆盖。
# 旧容器崩溃后,运行新的容器时可以直接将卷和挂载目录配置到新容器,这时数据用的还是旧容器的数据 docker run -d -p 89:80 -v /app/nghtml:/user/shar/nginx/html -v ngconfig:/etc/nginx --name app3 nginx

Docker 网络

容器之间的网络数据访问
每个容器启动时会自动加入docker的自动网络docker0(在服务器的ip配置中能看到docker0网卡),这样在这些容器之间就组建了一个局域网,使用容器IP+容器端口就能互相访问了
docker run -d -p 88:80 --name app1 nginx docker run -d -p 99:80 --name app2 nginx docker container inspect app1 # 查看容器app1的信息,能看到他的局域网IP地址 docker container inspect app2 # 查看容器app2的信息,能看到他的局域网IP地址 # 在app1容器内访问app2 docker exec -it app1 /bin/bash curl http://172.17.0.3:80
但是docker0不支持容器主机域名,所以我们需要自己创建一个自定义网络,并将容器加入到这个网络中,这个网络能够支持容器主机域名(这样容器的名字就可以当成主机域名作为稳定的访问地址)
docker network create mynet # 创建自定义网络 docker network ls # 查看所有网络 docker run -d -p 88:80 --name app1 --network mynet nginx # 启动容器并加入自定义网络 docker run -d -p 88:80 --name app2 --network mynet nginx docker container inspect app1 # 查看容器app1的信息,能看到他的局域网IP地址 docker container inspect app2 # 查看容器app2的信息,能看到他的局域网IP地址 # 在app1容器内访问app2 docker exec -it app1 /bin/bash curl http://app2:80

Docker Compose

容器批量管理工具,针对项目服务较多的工作;

命令式启动

以一个博客项目为例
#创建网络 docker network create blog #启动mysql docker run -d -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ -e MYSQL_DATABASE=wordpress \ -v mysql-data:/var/lib/mysql \ -v /app/myconf:/etc/mysql/conf.d \ --restart always --name mysql \ --network blog \ mysql:8.0 #启动wordpress docker run -d -p 8080:80 \ -e WORDPRESS_DB_HOST=mysql \ -e WORDPRESS_DB_USER=root \ -e WORDPRESS_DB_PASSWORD=123456 \ -e WORDPRESS_DB_NAME=wordpress \ -v wordpress:/var/www/html \ --restart always --name wordpress-app \ --network blog \ wordpress:latest

Compose启动

compose主要通过操作compose.yaml文件来实现批量操作

compose.yaml配置文件的编写

语法规范详见:官方文档
compose.yaml文件配置
name: myblog services: mysql: container_name: mysql image: mysql:8.0 ports: - "3306:3306" environment: - MYSQL_ROOT_PASSWORD=123456 - MYSQL_DATABASE=wordpress volumes: - mysql-data:/var/lib/mysql - /app/myconf:/etc/mysql/conf.d restart: always networks: - blog wordpress: image: wordpress ports: - "8080:80" environment: WORDPRESS_DB_HOST: mysql WORDPRESS_DB_USER: root WORDPRESS_DB_PASSWORD: 123456 WORDPRESS_DB_NAME: wordpress volumes: - wordpress:/var/www/html restart: always networks: - blog depends_on: - mysql volumes: mysql-data: wordpress: networks: blog:

compose批量启动

notion imagenotion image
docker compose up -d # up表示上线(第一次启动),-d:后台运行 docker compose -f compose.yaml up -d # 修改了配置文件,对其进行更新(只会重启修改过的容器) docker compose -f compose.yaml down # 下线(移除)容器,【会保留卷】 docker compose -f compose.yaml down --rmi -v # 下线(移除)容器;--rmi:同时删除容器对应的镜像;-v:同时删除容器映射的卷 # -f:使用指定文件来构建,不写-f则默认使用Dockerfile文件

制作镜像

Dockerfile文件

docker builder通过dockerfile文件的内容来制作镜像,所以制作镜像最主要的就是编写Dockerfile文件。
通常,Dockerfile 的第一行是 FROM 指令,它定义了镜像的基础环境。然而,如果你的机器不能联网,那么不能直接从官方 Docker Hub 或其他在线仓库拉取基础镜像。解决这个问题的办法有以下几种:
方法 1: 使用已有的本地基础镜像
方法 2: 离线获取基础镜像
  • 在可联网的机器上拉取镜像
  • 在联网机器上将镜像保存为 .tar 文件
  • 将镜像传输到离线机器
  • 在离线机器上加载镜像
方法 3:配置一个可用镜像源,阿里云主机可以参考这里配置
Dockerfile 中的指令是按顺序执行的,某些指令依赖于之前的指令的结果,所以编写时需要按照顺序编写。
notion imagenotion image
📌
Dockerfile文件配置参考
# 选择基础镜像 FROM python:3.9 # 维护者信息(已被 LABEL 替代) LABEL maintainer="your_email@example.com" # 设置构建时变量 ARG APP_VERSION=1.0 # 设置环境变量 ENV APP_HOME=/app # 创建工作目录 WORKDIR $APP_HOME # 复制当前目录的内容到容器中的工作目录 COPY . . # 安装所需的 Python 包 RUN pip install --no-cache-dir -r requirements.txt # 声明容器监听的端口 EXPOSE 5000 # 创建数据卷 VOLUME ["/data"] # 指定容器启动时运行的命令 CMD ["python", "app.py"] # 设置容器的入口点 ENTRYPOINT ["python"] # 指定运行容器时的用户 USER nobody

构建镜像

docker build -f Dockerfile -t my_python_app:v1.0 . # .:表示上下文路径,Docker 会在这个目录中查找 Dockerfile 和其他需要的文件。 docker build 可选参数: # -t(--tag):为镜像指定一个名称和标签;如:docker build -t my-image:latest .(将镜像命名为 my-image,标签为 latest) # -f(--file):指定 Dockerfile 的路径;如:docker build -f /path/to/Dockerfile .(使用指定路径的 Dockerfile 构建镜像) # --no-cache:在构建时不使用缓存;如:docker build --no-cache -t my-image .(强制重新构建所有层) # --pull:在构建之前尝试拉取最新的基础镜像;如:docker build --pull -t my-image .(确保使用最新的基础镜像) # --build-arg:传递构建时变量;如:docker build --build-arg MY_VAR=value .(在 Dockerfile 中使用 ARG 指令接收该变量) # --label:为镜像添加元数据标签;如:docker build --label version=1.0 .(为镜像添加版本标签) # --quiet(-q):只输出镜像 ID,不显示构建过程的详细信息;如:docker build -q -t my-image .(构建完成后只输出镜像 ID) # --rm:在构建完成后自动删除中间容器(默认值为 true);如:docker build --rm -t my-image .(构建完成后删除中间容器) # --target:指定多阶段构建中的目标阶段;如:docker build --target builder -t my-image .(构建指定的阶段) # --squash:将所有层压缩为一层(需要 Docker 版本支持);如:docker build --squash -t my-image .(减少镜像大小)

实操

官方前端案例:get started guide
  1. 克隆案例项目
    1. $ git clone https://github.com/docker/getting-started-app.git
  1. 创建项目镜像
    1. 创建Dockerfile文件
      1. $ cd /path/to/getting-started-app # 进入项目文件夹 $ touch Dockerfile # 创建Dockerfile文件
    2. 向文件内添加内容
      1. # syntax=docker/dockerfile:1 FROM node:18-alpine WORKDIR /app COPY . . RUN yarn install --production CMD ["node", "src/index.js"] EXPOSE 3000
        内容解释
        • # syntax=docker/dockerfile:1:指定 docker 语法版本
        • FROM node:18-alpine:基于基础镜像node:18-alpine
        • WORKDIR /app :设置了容器内的工作目录为/app
        • COPY . .:将当前目录下的所有文件和文件夹复制到容器的工作目录 /app 中
        • RUN yarn install --production :在工作路径下运行yarn install --production安装依赖,根据package.json 文件安装
        • CMD ["node", "src/index.js"]:指定了容器启动时要执行的默认命令,将运行 Node.js,并执行 src/index.js 文件。
        • EXPOSE 3000:将容器内的 3000 端口暴露给外部网络
    3. 在终端创建镜像
      1. $ docker build -t getting-started .
        指令解读
        • 由于指定了基础镜像,可能会下载一些依赖镜像层
        • -t 表示指定镜像的名称和标签的组合,默认使用 "latest" 标签
        • . 表示告诉Docker在当前目录下查找Dockerfile文件
        📌
        创建时指定平台
        $ docker build --platform linux/amd64 -t YOUR-USER-NAME/getting-started .
  1. 运行镜像创建容器
    1. $ docker run -dp 127.0.0.1:3000:3000 getting-started
      指令解读
      • docker run:这是运行 Docker 容器的命令。
      • -dp 127.0.0.1:3000:3000:这是用于设置容器的运行选项的部分。
        • -d 表示以后台(detached)模式运行容器,
        • -p 127.0.0.1:3000:3000 表示将主机的 127.0.0.1 的 3000 端口映射到容器的 3000 端口。
      • getting-started:这是指定要运行的 Docker 镜像的名称。
      查看运行结果:http://localhost:3000/
      📌
      停止容器运行:
      $ docker ps # 列出当前正在运行的 Docker 容器,看到容器 ID $ docker stop <容器ID>
  1. 更新项目内容,并重新制作镜像
    1. 修改项目文件:src/static/js/app.js第 56 行
      1. - <p className="text-center">No items yet! Add one above!</p> + <p className="text-center">You have no todo items yet! Add one above!</p>
    2. 重新构建镜像并实例化容器
      1. $ docker build -t getting-started . $ docker run -dp 127.0.0.1:3000:3000 getting-started
        📌
        删除旧容器:
        $ docker container ls -a # 查看所有状态的容器,看到容器 ID $ docker rm <容器ID> [<容器ID>2] # 重启一个运行中的容器,可批量操作
  1. 在 DockerHub 上分享镜像
    1. 在DockerHub上创建一个和项目文件夹同名仓库getting-started,并记住仓库名称前面的 Namespace 内容;
    2. 为本地镜像添加一个标签,便签为Namespace/getting-started
    3. 将镜像推送到DockerHub仓库,推送用新添加的标签名
      1. $ docker push anjhon/getting-started
官方Python 案例:Containerize a Python application
  1. 克隆案例项目
    1. $ git clone https://github.com/docker/python-docker
  1. 初始化 Docker
    1. $ docker init
      会新增一些文件
      ├── python-docker/ │ ├── app.py │ ├── requirements.txt │ ├── .dockerignore │ ├── compose.yaml │ ├── Dockerfile │ ├── README.Docker.md │ └── README.md
  1. 构建并启动容器(在项目文件夹下运行)
    1. $ docker compose up --build $ docker compose up --build -d # 后台运行 $ docker compose down # 停止运行
      指令解读
      • Docker Compose 是一个用于定义和管理多个 Docker 容器的工具;通过执行 docker compose up,可以启动和管理定义在 docker-compose.yml 文件中的一组容器
      • 指令将会读取当前目录下的 docker-compose.yml 文件,并根据其中定义的服务配置来启动容器。如果镜像不存在或具有更新,它将会在启动之前构建所需的镜像。
      • up 表示启动容器,
      • --build 表示在启动之前构建镜像
Python 案例 1 —— 强化学习(井字棋)
  1. 井字棋代码——from 刘建平
  1. 将文件放入一个空文件夹,并用pipreqs生成项目依赖文件
    1. pip install pipreqs pipreqs ./ --encoding='utf-8' --force
  1. 新建Dockerfile文件,文件内容如下
    1. FROM python:3.11.3-slim-buster ADD . /app WORKDIR /app RUN pip install -r requirements.txt CMD ["python", "/app/reinforcement_learning_fromPinard.py"]
      如果直接用python:3.11.3,则体积 900+M;Python官方镜像地址
  1. 构建镜像
    1. docker build -t tictactoe:v1 . # tictactoe:v1 镜像名称tictactoe,标签v1 # 这里的-t 表示设置一个名称和标签
  1. 运行镜像生成容器
    1. docker run -it --rm tictactoe:v1 bash # 进入容器后,用 Python 运行程训 python reinforcement_learning_fromPinard.py # 退出容器(如果在启动时加了--rm,则会在退出时删除容器) exit
      📌
      程序会先训练模型 10 万次,然后会出现提示框,可以人机对弈;九宫格对应的按键位置为 qwe asd zxc
      notion imagenotion image

推荐连接

  1. 官方文档
  1. DockerHub
  1. Docker一从入门到实践
  1. 使用Docker安装配置Jupyter并配置R语言与Python环境
  1. docker desktop ubuntu镜像_基于docker的python数据挖掘环境搭建(Jupyter notebook))
If you have any questions, please contact me.