在咱们代码人的日常中,你一定见过以下对话:
"又出bug了?""对,但我这边是好的啊!""你先等等,我看看你的环境…""我这Node版本是16,MySQL是5.7,Redis…""我这全是最新版…""……"
现在,docker来解决烦恼了。
1. Docker基础命令
先记录最常用的命令。以后忘记了方便查询。
1.1 镜像相关命令
# 搜索镜像
docker search nginx
# 拉取镜像
docker pull nginx:latest # 拉取最新版本
docker pull nginx:1.20.0 # 拉取特定版本
docker pull nginx@sha256:123... # 通过sha256拉取
# 列出本地镜像
docker images
docker image ls
# 查看镜像详细信息
docker inspect nginx
# 删除镜像
docker rmi nginx # 删除单个镜像
docker rmi $(docker images -q) # 删除所有镜像
docker image prune # 删除未使用的镜像
# 保存和加载镜像
docker save nginx > nginx.tar # 导出镜像到文件
docker load < nginx.tar # 从文件加载镜像
# 构建镜像
docker build -t myapp:1.0 . # 从当前目录的Dockerfile构建
docker build -f my.dockerfile . # 使用自定义Dockerfile
1.2 容器操作命令
# 创建并运行容器
docker run nginx # 简单运行
docker run -d nginx # 后台运行
docker run -it nginx bash # 交互式运行
docker run --name my-nginx nginx # 指定容器名称
# 常用运行参数
docker run \
-d \ # 后台运行
--name my-app \ # 容器名称
-p 8080:80 \ # 端口映射
-v /host/path:/container/path \ # 挂载卷
-e ENV_VAR=value \ # 环境变量
--network my-network \ # 指定网络
--restart always \ # 重启策略
nginx
# 容器生命周期管理
docker start my-nginx # 启动容器
docker stop my-nginx # 停止容器
docker restart my-nginx # 重启容器
docker kill my-nginx # 强制停止容器
# 查看容器
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器
docker top my-nginx # 查看容器进程
docker stats # 查看容器资源使用情况
# 容器日志和信息
docker logs my-nginx # 查看日志
docker logs -f my-nginx # 实时查看日志
docker inspect my-nginx # 查看容器详细信息
# 进入容器
docker exec -it my-nginx bash # 在运行的容器中执行命令
docker attach my-nginx # 连接到容器的主进程
# 文件操作
docker cp my-nginx:/etc/nginx/nginx.conf . # 从容器复制文件
docker cp nginx.conf my-nginx:/etc/nginx/ # 复制文件到容器
# 删除容器
docker rm my-nginx # 删除已停止的容器
docker rm -f my-nginx # 强制删除运行中的容器
docker container prune # 删除所有已停止的容器
1.3 网络管理命令
# 网络查看
docker network ls # 列出网络
docker network inspect bridge # 查看网络详情
# 网络创建
docker network create my-network # 创建网络
docker network create \
--driver overlay \
--subnet 10.0.0.0/24 \
--gateway 10.0.0.1 \
my-network
# 网络连接
docker network connect my-network my-nginx # 连接容器到网络
docker network disconnect my-network my-nginx # 断开网络连接
# 网络清理
docker network prune # 删除未使用的网络
1.4 数据卷命令
# 数据卷管理
docker volume create my-vol # 创建数据卷
docker volume ls # 列出数据卷
docker volume inspect my-vol # 查看数据卷详情
docker volume rm my-vol # 删除数据卷
docker volume prune # 删除未使用的数据卷
1.5 系统和清理命令
# 系统信息
docker info # 显示系统信息
docker version # 显示版本信息
docker events # 实时显示系统事件
# 清理命令
docker system df # 显示磁盘使用情况
docker system prune # 清理所有未使用的资源
docker system prune -a # 清理所有未使用的资源(包括未使用的镜像)
2. 重新理解docker
2.1 Docker不是虚拟机?
我之前是把Docker当作轻量级虚拟机。实际上:
# 查看容器内进程
docker exec container_name ps aux
# 在宿主机上也能看到对应进程
ps aux | grep container_process
🤔可以想一想:为什么容器内进程在宿主机上可见?这说明了什么?
关键点:
- Docker使用Linux的namespace机制实现隔离
- 容器和宿主机共享内核
- cgroups控制资源使用
这可以这么比喻:
虚拟机就像是在家里完整地建了一套新房子(包括地基、水电等基础设施),Docker 就是在已有的房子里隔出一个独立的房间,共用已有的水电等基础设施。
3.开始容器化
3.1 基础镜像的选择
常见基础镜像对比:
版本类型 | 大小 | 特点 | 适用场景 |
---|---|---|---|
latest | ~1GB | 完整工具链 | 开发测试 |
slim | ~200MB | 精简依赖 | 生产环境 |
alpine | ~50MB | 极度精简 | 特定场景 |
docker pull node:16
docker pull node:16-slim
docker pull node:16-alpine
3.2 Dockerfile举例
就拿我搭建的一个java的Dockerfile为例:
FROM harbor.test.com/test/centos:latest
LABEL description="ruoyi-java-backed-server"
ENV JAVA_HOME=/apps/soft/jdk-17.0.13
ENV PATH=$JAVA_HOME/bin:$PATH
COPY CentOS-Base.repo /etc/yum.repos.d/
RUN cd /etc/yum.repos.d/ && \
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && \
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* && \
yum clean all && \
yum makecache
RUN mkdir -p /apps/soft \
&& mkdir -p /apps/code/ruoyi
RUN yum install -y fontconfig && \
yum install -y dejavu-sans-fonts
ADD jdk-17.0.13.tar.gz /apps/soft
COPY ruoyi-admin.jar /apps/code/ruoyi
EXPOSE 8080
VOLUME /apps/code/ruoyi
CMD ["java","-jar","/apps/code/ruoyi/ruoyi-admin.jar"]
当然这是不够完美的,我专门找了一个完美的来对比
一个优化后的Node.js应用Dockerfile:
# 构建阶段
FROM node:16-slim as builder
WORKDIR /build
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 运行阶段
FROM node:16-slim
WORKDIR /app
COPY --from=builder /build/dist ./dist
COPY --from=builder /build/node_modules ./node_modules
COPY package*.json ./
USER node
EXPOSE 3000
CMD ["npm", "start"]
关键优化点:
- 多阶段构建减小最终镜像大小
- 合理的指令顺序利用缓存
- 使用非root用户运行
- 明确指定依赖版本
3.3 构建与运行
# 构建镜像
docker build -t myapp:1.0 .
# 运行容器
docker run -d \
--name myapp \
-p 3000:3000 \
-v logs:/app/logs \
--memory="512m" \
--cpus="1.0" \
myapp:1.0
当然还有更复杂的:
docker run -d
--name ruoyi-backed-server
-p 8080:8080
--link ruoyi-mysql-server:mysql-server
--link ruoyi-redis-server:redis-server
-v /usr/lib64:/usr/lib64:ro
-v /usr/share/fonts:/usr/share/fonts:ro
-e JAVA_OPTS="-Djava.awt.headless=true
-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"
-e LANG=C.UTF-8 harbor.test.com:80/test/backed:java-v17.0.13
4. 生产环境实战
4.1 Docker Compose
完整的docker-compose.yml示例:
version: "3.3"
services:
ruoyi-mysql-server:
build:
context: mysql/
dockerfile: Dockerfile
image: harbor.test.com/test/mysql:8.0.26
container_name: ruoyi-mysql-container
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
TZ: "Asia/Shanghai"
volumes:
- /apps/ruoyi/mysql/my.cnf:/etc/mysql/my.cnf
- /apps/ruoyi/mysql/conf.d:/etc/mysql/conf.d
- /apps/ruoyi/mysql/data:/var/lib/mysql
- /apps/ruoyi/mysql/logs:/var/log/mysql
networks:
default:
aliases:
- mysql-server
ruoyi-redis-server:
build:
context: redis/
dockerfile: Dockerfile
image: harbor.test.com/test/redis:latest
container_name: ruoyi-redis-container
ports:
- "6379:6379"
volumes:
- /apps/ruoyi/redis/data:/data
- /apps/ruoyi/redis/redis.conf:/etc/redis/redis.conf
networks:
default:
aliases:
- redis-server
ruoyi-backed-server:
build:
context: backend/
dockerfile: Dockerfile
image: harbor.test.com/test/centos:latest
container_name: ruoyi-backed-container
ports:
- "8080:8080"
volumes:
- /apps/ruoyi/backend:/apps/code/ruoyi
environment:
- JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"
- LANG=C.UTF-8
depends_on:
- ruoyi-mysql-server
- ruoyi-redis-server
ruoyi-nginx-server:
build:
context: nginx/
dockerfile: Dockerfile
image: harbor.test.com/test/nginx:alpine
container_name: ruoyi-nginx-container
ports:
- "80:80"
volumes:
- /apps/ruoyi/nginx/nginx.conf:/etc/nginx/nginx.conf
- /apps/ruoyi/nginx/conf.d:/etc/nginx/conf.d
- /apps/ruoyi/nginx/logs:/var/log/nginx
- /apps/ruoyi/nginx/ruoyi-ui:/data
depends_on:
- ruoyi-backed-server
5. 常见问题
5.1 构建失败
常见原因和解决方案:
- 构建上下文过大
# 使用.dockerignore
node_modules
npm-debug.log
- 网络问题
# 使用镜像加速
docker build --network host .
5.2 容器启动失败
排查步骤:
# 查看容器状态
docker ps -a
# 查看启动日志
docker logs container_id
# 进入容器排查
docker exec -it container_id sh
5.3 性能问题
# 查看容器资源使用
docker stats
# 查看详细指标
docker inspect container_id
写在最后
又把命令敲了一遍,但是以后还是可能忘,还是要多练,多部署几个项目就熟了。
当然,命令不是最重要的,忘了的话查起来很快。关键是流程要知道。