Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
2013年Docker诞生以来,容器化技术迅速发展,改变了软件开发、测试、部署的方式。2016年,Docker已经非常成熟,成为DevOps和云计算领域的标配技术。作为程序员,掌握Docker是必备技能之一。今天就来分享Docker容器化部署的完整指南。
Docker简介
1. 什么是Docker:
Docker是一个开源的应用容器引擎,基于Go语言开发,由dotCloud公司(后改名为Docker Inc.)于2013年推出。Docker可以让开发者将应用及其依赖打包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上运行。
Docker的核心概念:
- 镜像(Image):Docker镜像是一个只读的模板,包含运行应用所需的代码、运行时、库、环境变量、配置文件等。镜像可以用来创建Docker容器,类似于面向对象编程中的类。
- 容器(Container):Docker容器是镜像运行时的实例,是一个独立运行的应用或一组应用,以及它们的运行环境。容器可以被启动、停止、删除,类似于面向对象编程中的对象。
- 仓库(Repository):Docker仓库是存放镜像的地方,分为公共仓库和私有仓库。Docker Hub是最大的公共仓库,存放了大量官方和社区创建的镜像。
Docker的特点:
- 轻量级:容器共享主机内核,启动快,资源占用少,比虚拟机更轻量
- 可移植:一次构建,到处运行,容器可以在任何支持Docker的环境中运行
- 隔离性:容器之间相互隔离,应用和依赖运行在独立的环境中,互不干扰
- 标准化:Docker提供了标准化的打包、分发、部署方式,简化了应用的交付流程
- 可复制:容器可以快速复制和扩展,适合弹性伸缩和集群部署
- 版本控制:镜像支持版本控制,可以追溯历史版本,方便回滚
2. Docker与虚拟机的区别:
Docker容器和虚拟机(VM)都是虚拟化技术,但是它们有本质的区别:
| 特性 | Docker容器 | 虚拟机 |
|---|---|---|
| 虚拟化层次 | 操作系统级虚拟化 | 硬件级虚拟化 |
| 内核 | 共享主机内核 | 每个VM有独立内核 |
| 启动速度 | 秒级启动 | 分钟级启动 |
| 资源占用 | 轻量,MB级 | 重量,GB级 |
| 性能 | 接近原生性能 | 有一定性能损耗 |
| 隔离性 | 进程级隔离 | 完全隔离 |
| 可移植性 | 高,一次构建到处运行 | 较低,依赖虚拟化平台 |
简单来说,虚拟机是在硬件层面虚拟化,每个虚拟机都有完整的操作系统,资源占用大,启动慢;而Docker容器是在操作系统层面虚拟化,容器共享主机内核,只包含应用和依赖,资源占用小,启动快。
3. Docker的应用场景:
- 应用部署:将应用和依赖打包成镜像,快速部署到生产环境,避免环境不一致的问题
- 持续集成/持续部署(CI/CD):Docker与CI/CD工具结合,实现自动化构建、测试、部署
- 微服务架构:每个微服务打包成一个容器,独立部署、独立扩展、独立维护
- 开发环境:开发者可以用Docker快速搭建一致的开发环境,避免"在我机器上能跑"的问题
- 测试环境:测试人员可以用Docker快速创建和销毁测试环境,提高测试效率
- 弹性伸缩:容器可以快速启动和停止,配合编排工具实现自动弹性伸缩
- 多租户隔离:每个租户的应用运行在独立的容器中,实现资源隔离和安全隔离
- 遗留应用迁移:将老旧应用打包成容器,迁移到新的服务器或云平台
Docker安装
1. CentOS安装Docker:
# 卸载旧版本
sudo yum remove docker docker-common docker-selinux docker-engine
# 安装依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加Docker源(使用国内阿里云源,速度更快)
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安装Docker CE
sudo yum install -y docker-ce
# 启动Docker
sudo systemctl start docker
# 设置开机自启
sudo systemctl enable docker
# 验证安装
docker --version
docker info2. Ubuntu安装Docker:
# 卸载旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc
# 更新apt包索引
sudo apt-get update
# 安装依赖
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
# 添加Docker官方GPG密钥(使用国内源)
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# 添加Docker源
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# 更新apt包索引
sudo apt-get update
# 安装Docker CE
sudo apt-get install -y docker-ce
# 启动Docker
sudo systemctl start docker
# 设置开机自启
sudo systemctl enable docker
# 验证安装
docker --version3. 配置Docker镜像加速:
由于国内网络原因,从Docker Hub拉取镜像速度较慢,建议配置国内镜像加速器,如阿里云、网易云、中科大等。
# 创建Docker配置目录
sudo mkdir -p /etc/docker
# 配置镜像加速器(以阿里云为例,需要替换为自己的加速器地址)
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://your-mirror.mirror.aliyuncs.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
# 重启Docker
sudo systemctl daemon-reload
sudo systemctl restart docker
# 验证配置
docker infoDocker常用命令
1. 镜像操作:
# 搜索镜像
docker search nginx
# 拉取镜像
docker pull nginx
docker pull nginx:1.21
docker pull ubuntu:20.04
# 列出本地镜像
docker images
docker image ls
# 查看镜像详情
docker inspect nginx
# 删除镜像
docker rmi nginx
docker image rm nginx
docker rmi -f nginx # 强制删除
# 导出镜像
docker save -o nginx.tar nginx
# 导入镜像
docker load -i nginx.tar
# 给镜像打标签
docker tag nginx:latest myregistry.com/nginx:1.0
# 推送镜像到仓库
docker push myregistry.com/nginx:1.02. 容器操作:
# 创建并启动容器
docker run nginx
docker run -d nginx # 后台运行
docker run -d --name mynginx nginx # 指定容器名
docker run -d -p 8080:80 nginx # 端口映射(主机8080映射到容器80)
docker run -d -v /host/path:/container/path nginx # 挂载数据卷
docker run -e ENV_VAR=value nginx # 设置环境变量
docker run -it ubuntu /bin/bash # 交互式运行
# 列出容器
docker ps # 运行中的容器
docker ps -a # 所有容器(包括已停止的)
docker container ls -a
# 启动/停止/重启容器
docker start mynginx
docker stop mynginx
docker restart mynginx
# 进入容器
docker exec -it mynginx /bin/bash
docker attach mynginx # 附加到容器(不推荐,退出会停止容器)
# 查看容器日志
docker logs mynginx
docker logs -f mynginx # 实时跟踪日志
docker logs --tail 100 mynginx # 查看最后100行
# 查看容器详情
docker inspect mynginx
# 查看容器内进程
docker top mynginx
# 复制文件到容器/从容器复制
docker cp /host/path mynginx:/container/path
docker cp mynginx:/container/path /host/path
# 删除容器
docker rm mynginx
docker rm -f mynginx # 强制删除(运行中的也能删)
docker container prune # 删除所有已停止的容器
# 暂停/恢复容器
docker pause mynginx
docker unpause mynginx3. 数据卷操作:
# 创建数据卷
docker volume create myvolume
# 列出数据卷
docker volume ls
# 查看数据卷详情
docker volume inspect myvolume
# 使用数据卷启动容器
docker run -d -v myvolume:/data nginx
# 挂载主机目录作为数据卷
docker run -d -v /host/data:/data nginx
# 删除数据卷
docker volume rm myvolume
docker volume prune # 删除所有未使用的数据卷4. 网络操作:
# 列出网络
docker network ls
# 创建网络
docker network create mynetwork
docker network create --driver bridge mynetwork
# 查看网络详情
docker inspect mynetwork
# 容器连接到网络
docker network connect mynetwork mycontainer
# 容器断开网络
docker network disconnect mynetwork mycontainer
# 删除网络
docker network rm mynetwork
docker network prune # 删除所有未使用的网络Dockerfile编写
Dockerfile是用来构建Docker镜像的文本文件,包含了一系列指令和命令。通过Dockerfile,我们可以自动化地构建镜像,实现镜像的版本控制和可复制性。
1. Dockerfile常用指令:
# FROM:指定基础镜像,必须是第一条指令
FROM ubuntu:20.04
# MAINTAINER:维护者信息(已废弃,推荐用LABEL)
MAINTAINER Your Name <your@email.com>
# LABEL:添加元数据
LABEL maintainer="Your Name <your@email.com>"
LABEL version="1.0"
LABEL description="This is a custom image"
# RUN:执行命令(构建时执行)
RUN apt-get update && apt-get install -y nginx
RUN echo "Hello Docker" > /var/www/html/index.html
# CMD:容器启动时执行的命令(可以被docker run参数覆盖)
CMD ["nginx", "-g", "daemon off;"]
# ENTRYPOINT:容器启动时执行的命令(不会被docker run参数覆盖,参数会追加)
ENTRYPOINT ["nginx", "-g", "daemon off;"]
# WORKDIR:设置工作目录
WORKDIR /app
# COPY:复制文件到镜像中(从构建上下文复制)
COPY . /app
COPY package.json /app/package.json
# ADD:复制文件到镜像中(支持URL和自动解压tar)
ADD app.tar.gz /app
ADD https://example.com/file.txt /app
# ENV:设置环境变量
ENV NODE_ENV=production
ENV PORT=8080
# EXPOSE:声明容器监听的端口
EXPOSE 80
EXPOSE 443
# VOLUME:声明数据卷
VOLUME ["/data"]
# USER:指定运行用户
USER nginx
# ARG:构建参数(构建时传入,用--build-arg)
ARG VERSION=1.0
ENV APP_VERSION=$VERSION
# HEALTHCHECK:健康检查
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost/ || exit 12. Dockerfile示例:Nginx镜像:
# 基础镜像
FROM nginx:1.21-alpine
# 维护者
LABEL maintainer="Your Name <your@email.com>"
# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 复制网站文件
COPY ./html /usr/share/nginx/html
# 复制Nginx配置
COPY ./nginx.conf /etc/nginx/nginx.conf
# 暴露端口
EXPOSE 80 443
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s CMD wget -q --spider http://localhost/ || exit 1
# 启动Nginx
CMD ["nginx", "-g", "daemon off;"]3. Dockerfile示例:Node.js应用:
# 基础镜像
FROM node:16-alpine
# 维护者
LABEL maintainer="Your Name <your@email.com>"
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000
# 先复制package.json,利用Docker缓存
COPY package*.json ./
# 安装依赖
RUN npm install --production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:3000/health || exit 1
# 启动应用
CMD ["node", "app.js"]4. Dockerfile最佳实践:
- 使用轻量级基础镜像:优先使用alpine版本镜像,体积小,安全
- 利用构建缓存:将变化少的指令放在前面(如安装依赖),变化多的放在后面(如复制代码),充分利用Docker缓存
- 合并RUN指令:多个RUN指令合并成一个,减少镜像层数,减小镜像体积
- 清理缓存:安装完依赖后及时清理包管理器缓存,减小镜像体积
- 使用.dockerignore:排除不需要的文件,减小构建上下文,加快构建速度
- 不要在镜像中存储敏感信息:密码、密钥等不要写在Dockerfile中,使用环境变量或密钥管理
- 指定具体版本标签:不要用latest标签,指定具体版本,保证可重复性
- 多阶段构建:使用多阶段构建,编译环境和运行环境分离,减小最终镜像体积
- 非root用户运行:创建普通用户,用USER指令切换,提高安全性
5. .dockerignore示例:
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.env.local
*.log
.DS_Store
.idea
.vscode
dist
build
coverageDocker Compose
Docker Compose是Docker官方的编排工具,用于定义和运行多容器Docker应用。通过一个YAML文件来配置应用的服务,然后用一条命令就可以创建并启动所有服务。
1. 安装Docker Compose:
# 下载Docker Compose(使用国内镜像加速)
sudo curl -L "https://get.daocloud.io/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose
# 验证安装
docker-compose --version2. docker-compose.yml示例:LNMP环境:
version: '3.8'
services:
# Nginx服务
nginx:
image: nginx:1.21-alpine
container_name: lnmp-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./www:/var/www/html
- ./logs/nginx:/var/log/nginx
depends_on:
- php
- mysql
restart: always
networks:
- lnmp-network
# PHP服务
php:
image: php:7.4-fpm-alpine
container_name: lnmp-php
volumes:
- ./www:/var/www/html
- ./php/php.ini:/usr/local/etc/php/php.ini
depends_on:
- mysql
- redis
restart: always
networks:
- lnmp-network
# MySQL服务
mysql:
image: mysql:5.7
container_name: lnmp-mysql
ports:
- "3306:3306"
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/my.cnf:/etc/mysql/my.cnf
environment:
MYSQL_ROOT_PASSWORD: root123456
MYSQL_DATABASE: blog
MYSQL_USER: blog
MYSQL_PASSWORD: blog123456
restart: always
networks:
- lnmp-network
# Redis服务
redis:
image: redis:6-alpine
container_name: lnmp-redis
ports:
- "6379:6379"
volumes:
- ./redis/data:/data
- ./redis/redis.conf:/etc/redis/redis.conf
command: redis-server /etc/redis/redis.conf
restart: always
networks:
- lnmp-network
# 网络
networks:
lnmp-network:
driver: bridge3. Docker Compose常用命令:
# 启动所有服务(后台运行)
docker-compose up -d
# 启动指定服务
docker-compose up -d nginx
# 停止所有服务
docker-compose down
# 停止并删除容器、网络、卷
docker-compose down -v
# 查看服务状态
docker-compose ps
# 查看服务日志
docker-compose logs
docker-compose logs -f nginx
docker-compose logs --tail 100
# 进入容器
docker-compose exec nginx /bin/sh
docker-compose exec php /bin/sh
# 构建/重新构建镜像
docker-compose build
docker-compose build --no-cache # 不使用缓存
# 拉取镜像
docker-compose pull
# 重启服务
docker-compose restart
docker-compose restart nginx
# 暂停/恢复服务
docker-compose pause
docker-compose unpause
# 查看配置
docker-compose configDocker部署实战:部署PHP博客
下面以部署一个PHP+MySQL+Redis的博客为例,演示如何用Docker Compose快速部署。
1. 项目结构:
blog/
├── docker-compose.yml # Docker Compose配置
├── nginx/
│ ├── nginx.conf # Nginx主配置
│ └── conf.d/
│ └── blog.conf # 博客站点配置
├── php/
│ └── php.ini # PHP配置
├── mysql/
│ ├── my.cnf # MySQL配置
│ └── data/ # MySQL数据目录
├── redis/
│ ├── redis.conf # Redis配置
│ └── data/ # Redis数据目录
├── logs/
│ ├── nginx/ # Nginx日志
│ └── php/ # PHP日志
└── www/ # 网站根目录
└── index.php2. nginx/conf.d/blog.conf:
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html;
# 伪静态
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP处理
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|webp)$ {
expires 30d;
access_log off;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
}3. www/index.php:
<?php
// 连接MySQL
$pdo = new PDO('mysql:host=mysql;dbname=blog;charset=utf8mb4', 'blog', 'blog123456');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 连接Redis
$redis = new Redis();
$redis->connect('redis', 6379);
// 测试
echo "<h1>Hello Docker!</h1>";
echo "<p>PHP版本: " . phpversion() . "</p>";
// MySQL测试
$stmt = $pdo->query("SELECT VERSION() as version");
$mysqlVersion = $stmt->fetch(PDO::FETCH_ASSOC)['version'];
echo "<p>MySQL版本: {$mysqlVersion}</p>";
// Redis测试
$redis->set('test', 'Hello Redis!');
$redisTest = $redis->get('test');
echo "<p>Redis测试: {$redisTest}</p>";
echo "<p>博客部署成功!</p>";4. 启动服务:
# 进入项目目录
cd /path/to/blog
# 启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f
# 访问网站
# 浏览器打开 http://localhost5. 常用运维命令:
# 重启Nginx
docker-compose restart nginx
# 重新加载Nginx配置
docker-compose exec nginx nginx -s reload
# 进入MySQL
docker-compose exec mysql mysql -u root -p
# 备份数据库
docker-compose exec mysql mysqldump -u root -p blog > backup.sql
# 导入数据库
docker-compose exec -T mysql mysql -u root -p blog < backup.sql
# 查看Redis
docker-compose exec redis redis-cli
# 查看PHP日志
docker-compose logs php
# 更新代码后重启PHP
docker-compose restart phpDocker安全加固
- 不要用root用户运行容器:在Dockerfile中创建普通用户,用USER指令切换,容器内应用以普通用户运行
- 不要在镜像中存储敏感信息:密码、密钥、证书等不要写在Dockerfile或代码中,使用环境变量、Docker secrets或密钥管理工具
- 限制容器资源:启动容器时用--memory、--cpus等参数限制内存和CPU使用,防止容器占用过多资源
- 只读文件系统:用--read-only参数将容器根文件系统设为只读,需要写入的目录用数据卷挂载
- 禁用不需要的能力:用--cap-drop=ALL禁用所有Linux capabilities,只添加需要的能力
- 不要使用--privileged:除非必要,不要使用特权模式,特权模式容器拥有主机所有权限,非常危险
- 及时更新基础镜像:定期更新基础镜像,修复已知安全漏洞
- 扫描镜像漏洞:使用Trivy、Clair等工具扫描镜像中的安全漏洞
- 限制容器网络:使用自定义网络,不要用--network=host,容器之间只开放必要端口
- 使用可信镜像:只从可信的仓库拉取镜像,优先使用官方镜像,不要随意使用不明来源的镜像
学习建议
- 动手实践:Docker是实践性很强的技术,光看教程学不会,一定要多动手。在自己的电脑或服务器上安装Docker,跑几个容器,写几个Dockerfile,用Docker Compose部署几个应用
- 理解核心概念:镜像、容器、仓库、数据卷、网络,这些核心概念一定要理解清楚,这是学好Docker的基础
- 掌握常用命令:Docker命令很多,不需要全部记住,但是常用的镜像操作、容器操作、Docker Compose命令一定要熟练
- 学会写Dockerfile:Dockerfile是构建镜像的基础,要掌握常用指令,学会写高效、安全的Dockerfile
- 学习Docker Compose:实际项目中通常是多容器应用,Docker Compose是必备技能,要学会用docker-compose.yml编排多容器应用
- 了解容器编排:如果想深入学习,可以了解Kubernetes(K8s),它是目前最流行的容器编排工具,用于大规模容器集群管理
- 结合实际项目:把自己的项目用Docker部署,在实践中学习和提高。可以从简单的静态网站开始,逐步到PHP/Node.js应用,再到微服务架构
总结
Docker是现代软件开发和部署的革命性技术,它改变了应用的打包、分发、部署方式,让"一次构建,到处运行"成为现实。掌握Docker,不仅能提高开发和部署效率,还能让我们更好地理解微服务、DevOps、云计算等现代技术理念。
Docker的学习曲线并不陡峭,核心概念不多,常用命令也不难掌握。关键是要多动手实践,在实际项目中应用和提高。从跑一个简单的容器开始,到写Dockerfile,再到用Docker Compose编排多容器应用,逐步深入,相信你很快就能掌握Docker。
容器化是未来的趋势,Docker作为容器技术的代表,已经成为程序员的必备技能。希望这篇指南能帮助你入门Docker,开启容器化之旅!
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录