Docker:基本概念与快速入门
在如今的开发和运维圈子里,Docker 几乎成了人人必聊的话题。它不仅仅是一个工具,更彻底改变了我们打包、交付和运行软件的方式。不管你是写后端的、搞前端的,还是负责运维的,掌握 Docker 都能让你的工作轻松不少。今天,我们就来聊聊 Docker 的核心逻辑,顺便动手跑几个例子,帮你快速入门。
一、为什么 Docker 这么火?
在 Docker 出现之前,程序员最怕听到的一句话大概就是:"在我电脑上是好的啊,怎么到服务器就不行了?"
这就是典型的"环境一致性"难题。本地跑得好好的,一部署到测试或生产环境就各种报错。原因五花八门:操作系统不一样、依赖库版本冲突、环境配置没对齐......为了解决这些坑,大家以前常用虚拟机(VM)。虚拟机通过模拟硬件,让你在一台物理机上跑好几个独立的操作系统。虽然隔离性做到了,但代价也不小:启动慢得像蜗牛,吃内存和硬盘像饿狼,体积还特别大。
Docker 的出现就是为了找个平衡点:既要隔离,又要轻量。它不需要模拟硬件,也不需要跑一个完整的操作系统,而是直接共享宿主机的内核,通过容器技术做进程级的隔离。结果就是:Docker 容器启动只需几毫秒,占用资源极少,体积也小巧玲珑。
二、搞懂 Docker 的"三板斧"
想玩转 Docker,得先搞清楚三个核心概念:镜像、容器和仓库。
1. 镜像
镜像就是一个只读的"模板"。你可以把它想象成 Java 里的"类",或者是一张施工蓝图。里面包含了运行程序所需的一切:代码、运行环境、库、配置文件等等。
Docker 镜像有个很棒的设计叫"分层存储"。每一层都是只读的,当你想修改镜像(比如装个新软件),其实是在当前层上面加了个新的可写层。这样不仅省空间,构建和分发镜像也快得飞起。
2. 容器
容器就是镜像跑起来的实例。如果镜像是"类",那容器就是"new"出来的"对象"。容器是活的,你可以创建、启动、停止甚至删除它。
容器之间是互相隔离的,各有各的文件系统、网络和进程空间。这就保证了应用之间不会打架,也保证了你在哪跑这个应用,环境都是一样的。
3. 仓库
仓库就是存放镜像的地方。这就像存代码的 GitHub,Docker 也有自己的镜像托管服务,最出名的是 Docker Hub。你可以把自己做好的镜像推上去,也可以把别人分享的镜像拉下来用。
三、Docker 和虚拟机有啥区别?
为了更直观地感受 Docker 的优势,我们把它和传统虚拟机做个对比:
- 架构:虚拟机需要 Hypervisor 层和完整的 Guest OS;Docker 直接用宿主机的内核,不需要 Guest OS,只跑应用和依赖。
- 启动速度:虚拟机启动要几分钟,毕竟要引导整个系统;Docker 容器是毫秒级,因为只是启动一个进程。
- 性能:虚拟机有硬件模拟和指令转换,性能损耗大;Docker 容器几乎和原生应用性能一样。
- 体积:虚拟机镜像通常几个 GB 起步;Docker 镜像通常只有几十 MB 到几百 MB。
四、动手试一试:Docker 快速实战
光说不练假把式,直接上手操作。
1. 安装 Docker
Docker 支持 Linux、Windows 和 macOS。
- Linux :用包管理器就行,比如 Ubuntu 上执行
sudo apt-get install docker.io。 - Windows/Mac:建议直接装 Docker Desktop,有图形界面,对新手非常友好。
装好后,打开终端(或命令行),输入:
bash
docker --version
如果能显示出版本号,那就搞定了。
2. run 第一个容器
我们来跑一个经典的 Nginx Web 服务器。只需一行命令:
bash
docker run -d -p 8080:80 --name my-web-server nginx
解释一下这行命令:
docker run:运行新容器的指令。-d:后台运行。-p 8080:80:端口映射,把宿主机的 8080 端口映射到容器里的 80 端口。--name my-web-server:给容器起个好记的名字。nginx:指定用的镜像名,Docker 会自动从 Docker Hub 拉取最新版的 nginx。
跑完后,浏览器打开 http://localhost:8080,你就能看到 Nginx 的欢迎页了。
3. 常用管理命令
掌握这几个核心命令,日常基本够用:
-
看正在跑的容器 :
bashdocker ps -
看所有容器(包括停了的) :
bashdocker ps -a -
停容器 :
bashdocker stop my-web-server -
启动已停的容器 :
bashdocker start my-web-server -
删容器 :
bashdocker rm my-web-server
五、构建自己的镜像
用现成的镜像很爽,但实际开发中,我们得把自己的代码打包进去。这就需要写 Dockerfile。
Dockerfile 其实就是一个文本文件,里面写了一堆构建指令。下面我们用一个简单的 Python Web 应用举例。
先建个 app.py 文件:
python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello from Docker!"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
然后在同目录下建个 Dockerfile,内容如下:
dockerfile
# 用官方 Python 运行时做基础镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 把当前目录下的文件拷到容器的 /app 目录
COPY . /app
# 安装依赖
RUN pip install flask
# 声明容器运行时监听的端口
EXPOSE 5000
# 定义容器启动后运行的命令
CMD ["python", "app.py"]
接着,用 docker build 命令构建镜像:
bash
docker build -t my-python-app .
构建完成后,运行你的镜像:
bash
docker run -d -p 5000:5000 my-python-app
访问 http://localhost:5000,你就能看到 "Hello from Docker!" 了。
六、数据管理与持久化
默认情况下,容器里的文件系统是临时的。容器一删,里面的数据(比如日志、数据库文件)也就没了。为了解决这个问题,Docker 提供了数据卷和挂载主机目录的功能。
比如我们要跑个 MySQL 数据库,想把数据持久化存到宿主机上:
bash
docker run -d \
--name my-mysql \
-e MYSQL_ROOT_PASSWORD=example \
-v /my/own/datadir:/var/lib/mysql \
mysql:tag
这里的 -v /my/own/datadir:/var/lib/mysql 参数,把宿主机的 /my/own/datadir 目录挂载到了容器里的 /var/lib/mysql 目录。这样,就算容器删了,数据库文件还安全地躺在你的宿主机里。
七、总结
Docker 通过容器化技术,把应用和它依赖的环境打包在一起,真正实现了"一次构建,到处运行"。它不仅解决了开发和生产环境不一致的老大难问题,还极大地简化了部署和运维的流程。
这篇文章我们介绍了 Docker 的基本概念、它和虚拟机的区别、基本的容器操作以及怎么构建自定义镜像。当然,这只是 Docker 的冰山一角,后面你还可以去探索 Docker Compose(多容器编排)、Docker Network(容器网络)等更高级的玩法。