入门级开发者常常面临代码更新、发布和部署效率低下,以及环境一致性难以维护等痛点。在开发环境中运行顺畅的代码,换一台机器就可能报错。在云计算时代,使用传统方式部署代码显得过时。本文将向您介绍 Docker。
Docker 基于 Go 语言,遵循 Apache 2.0 开源协议,是一种应用容器引擎。这种容器化技术让开发者能够将应用程序及其依赖打包成轻量级、可移植的容器。这些容器可以在任何流行的 Linux 机器上部署,无需担心环境差异。

Docker 与虚拟机(VM)
如上所述,Docker 利用了虚拟化技术。谈到虚拟化,就不得不提虚拟机(VM)。由于两者都依赖虚拟化,自然会让人好奇它们之间的区别。我们来深入探讨一下。
首先,看一个典型的 VM 架构图。在基础设施(代表底层硬件)之上,有一个 hypervisor(虚拟机监视器)。它作为物理服务器和操作系统之间的中介,允许多个操作系统和应用程序共享底层硬件。虚拟机在宿主机操作系统之上运行多个不同的操作系统,并利用 hypervisor 访问底层硬件。
如果你需要运行三个隔离的应用程序,就需要创建三个虚拟机。这意味着 hypervisor 之上要运行三个操作系统,导致巨大的资源开销。

典型的 VM 架构图
(注:图中应在 Hypervisor 上方显示 Host Operating System)
相比之下,Docker 非常轻量。它的守护进程(Docker Daemon)取代了 hypervisor,直接运行在操作系统之上。应用程序的源代码和依赖被打包成 Docker 镜像。然后 Docker 引擎用这个镜像创建容器。不同的应用程序在隔离的容器中运行。
此外,Docker 守护进程直接与操作系统通信,为 Docker 容器分配资源。由于没有完整操作系统的开销,容器启动时间从虚拟机的几分钟缩短到 Docker 容器的毫秒级,大大提高了效率,并节省了大量磁盘空间和其他系统资源。
尽管 Docker 优势明显,但它并不能完全取代虚拟机。每种技术各有千秋。虚拟机擅长隔离整个运行时环境,云提供商通常通过虚拟机来隔离用户。而 Docker 通常隔离不同的应用程序。
如何使用 Docker
Docker 安装(以 CentOS 7 为例)
- 安装必要的系统工具:
yum install -y yum-utils device-mapper-persistent-data lvm2
- 更新系统内核和 yum 缓存:
yum update
yum makecache fast
- 安装 Docker 并启动:
yum -y install docker-ce
systemctl start docker
- 测试 Docker 是否安装成功:
docker run hello-world
如果屏幕上显示 “Hello from Docker”,恭喜你!安装完成。
概念
在深入学习 Docker 之前,先了解几个关键概念,以便更顺畅地学习。
- Docker 镜像:Docker 镜像是用于创建 Docker 容器的模板
- Docker 容器:Docker 通过镜像创建容器,用于运行一组独立的应用程序
- Docker 仓库:用于保存镜像的代码仓库
通常,我们从 Docker 仓库下载合适的镜像,然后用它创建容器来运行我们的应用程序。
示例
通过两个常见示例来连接这些概念,说明如何使用 Docker。
使用 Docker 安装 Python
如前所述,使用 Docker 容器的第一步是从仓库下载对应的镜像。这就引出了本教程的第一个命令:
docker search
- 用途: 在镜像仓库中搜索特定镜像。
- 语法:
docker search [OPTIONS] TERM - 示例:
docker search python - 说明: 在仓库中搜索与 Python 相关的镜像。
[root@novita ~]# docker search python
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/python Python is an interpreted, interactive, obj... 4356 [OK]
docker.io docker.io/django Django is a free web application framework... 856 [OK]
docker.io docker.io/pypy PyPy is a fast, compliant alternative impl... 196 [OK]
docker.io docker.io/kaggle/python Docker image for Python scripts run on Kaggle 125 [OK]
docker.io docker.io/arm32v7/python Python is an interpreted, interactive, obj... 38
docker.io docker.io/centos/python-35-centos7 Platform for building and running Python 3... 36
我们选择官方镜像,标签(版本)为 3.7。
docker pull
- 用途: 从镜像仓库拉取或更新指定镜像。
- 语法:
docker pull [OPTIONS] NAME:TAG - 示例:
docker pull python:3.7 - 说明: 从仓库下载标签为 3.7 的 Python 镜像。
[root@novita ~]# docker pull python:3.7
Trying to pull repository docker.io/library/python ...3.7: Pulling from docker.io/library/python
5ae19949497e: Downloading [=============> ] 13.72 MB/50.38 MB
ed3d96a2798e: Download complete
f12136850781: Downloading [============================================> ] 8.789 MB/9.978 MB
1a9ad5d5550b: Downloading [==> ] 2.628 MB/51.77 MB
6f18049a0455: Waiting
ce39fa9d79d1: Waiting
Digest: sha256:d8718f4c8f28360c88d2d8b53681edb3c95e6a7bacedabd32eb5b1d120a75dc5
Status: Downloaded newer image for docker.io/python:3.7
Docker 现已下载指定镜像。查看现有的 Docker 镜像:
docker images
- 用途: 列出本地镜像。
- 语法:
docker images [OPTIONS] [REPOSITORY[:TAG]] - 示例:
docker images - 说明: 查看所有本地 Docker 镜像。
[root@novita ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/python 3.7 42d620af35be 6 days ago 918 MB
docker.io/rabbitmq 3-management 7aae48fa6ef6 7 days ago 179 MB
docker.io/golang latest f50db16df5da 9 days ago 774 MB
python3.7 镜像已存在。我们用该镜像创建一个容器。
docker run
创建容器之前,简单提一下 ID。在 Docker 中,ID 唯一标识镜像或容器。我们通过 “命令 + ID” 来交互。例如,前面代码中 python3.7 的镜像 ID 是 42d620af35be。
- 用途: 创建一个新容器。
- 语法:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
为了测试 Python 环境,我们在本地创建一个 hello.py 文件:
#!/usr/bin/python
import sys
print("Hello, Docker!")
print(sys.version) # Output the Python version number
假设这段代码保存在 /root/code/python 下:
[root@novita python]# docker run -v $PWD:/usr/src/code -w /usr/src/code python:3.7 python hello.py
Hello, Docker!
3.7.4 (default, Jul 13 2019, 14:04:11) [GCC 8.3.0]
我们来分解一下这个命令:
docker run:创建容器。-v $PWD:/usr/src/code:将本地目录挂载到 Docker 容器中。这里将执行命令所在的目录挂载到容器内的 /usr/src/code。冒号分隔本地路径和容器路径。可以使用绝对路径代替$PWD。-w /usr/src/code:设置容器的工作目录。由于 Python 代码目录被挂载到 /usr/src/code,我们将其设为工作目录。python:3.7:指定镜像。也可以使用镜像 ID。python hello.py:在容器中执行此命令。
思考题: 如果 /root/data/ 下有一个 hello.go 文件,你想使用镜像 ID 为 f50db16df5da 的 Golang 容器运行它,命令应该是什么?(提示:运行 Go 代码的命令是 go run FILENAME)
使用 Docker 安装 MariaDB
假设你现在可以搜索并下载 MariaDB 镜像,我们来重点讨论如何启动它。
像数据库这样的服务需要在宿主机上开放相应端口。如何用 Docker 实现这一点?我们使用端口映射,类似于挂载目录。
[root@novita python]# docker run -d -v /data/mysql/:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --restart unless-stopped 3a2ef06682ac
-d:后台运行容器。-p 3306:3306:将容器内的 3306 端口映射到宿主机的 3306 端口。-e MYSQL_ROOT_PASSWORD=123456:将 MariaDB 的 root 密码设置为 123456。--restart unless-stopped:如果容器意外停止,自动重启。3a2ef06682ac:用于创建容器的镜像 ID。
现在,验证数据库服务是否正在运行:
docker ps
- 用途: 列出容器。
- 语法:
docker ps [OPTIONS]
[root@novita ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
107b52416c13 3a2ef06682ac "docker-entrypoint..." 5 minutes ago Up 5 minutes 0.0.0.0:3306->3306/tcp quizzical_mcnulty
接下来,进入容器的内部环境。
docker exec
- 用途: 在运行中的容器中执行命令。
- 语法:
docker exec [OPTIONS] CONTAINER COMMAND [ARG...] - 示例:
docker exec -it 107b52416c13 bash - 说明: 访问 ID 为 107b52416c13 的容器并执行
bash命令。
进入容器后,可以像在普通 Linux 环境中一样交互。使用之前设置的凭据即可访问 MariaDB。
[root@novita ~]# docker exec -it 107b52416c13 bash
root@107b52416c13:/# mysql -u root -p123456
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.4.6-MariaDB-1:10.4.6+maria~bionic mariadb.org binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
到目前为止,你已经学到了 Docker 的基础知识。试着探索更多内容。
Novita AI 是一个一站式云平台,助力您的 AI 雄心。通过无缝集成的 API、无服务器计算和 GPU 加速,我们提供成本效益高的工具,助您快速构建和扩展 AI 驱动的业务。消除基础设施烦恼,免费开始使用 —— Novita AI 让您的 AI 梦想成为现实。
