docker实战:基础操作、镜像打包、网络、容器编排

目录

操作

[打包镜像(docker build)](#打包镜像(docker build))

网络

[容器编排(docker compose)](#容器编排(docker compose))


操作

镜像操作:

复制代码
docker images          # 查看镜像
docker pull nginx      # 拉取镜像  
docker rmi nginx       # 删除镜像
docker build -t my-app .  # 构建镜像

容器操作:

复制代码
docker ps              # 查看容器
docker run nginx       # 启动容器
docker stop 容器名      # 停止容器
docker start 容器名     # 启动容器
docker rm 容器名        # 删除容器
docker exec -it 容器名 bash  # 进入容器

日志和监控

复制代码
docker logs 容器名      # 查看日志
docker logs -f 容器名   # 实时日志
docker stats           # 资源监控
docker inspect 容器名   # 查看详情

清理

复制代码
docker container prune  # 清理停止的容器
docker image prune      # 清理悬空镜像
docker volume prune     # 清理未使用的卷
docker system prune     # 清理所有未使用的资源

启动

docker run 常用参数

参数 说明 示例
-d 后台运行 docker run -d nginx
-it 交互模式 docker run -it ubuntu bash
-p 端口映射 -p 8080:80
-v 挂载卷 -v /host:/container
-e 环境变量 -e KEY=value
--name 容器名称 --name my-app
--rm 自动删除 --rm
--network 网络设置 --network my-net

连接

docker exec 常用参数

参数 说明 示例
-it 交互模式 docker exec -it 容器名 bash
-u 指定用户 -u root
-e 环境变量 -e VAR=value

打包镜像(docker build)

docker使用docker file来将指定资源打包成镜像,docker提供了一套命令来编写docker file:

  • from,指定基础镜像

  • run,执行命令

  • copy,复制文件

  • add,添加文件

  • workdir,工作目录

  • expose,暴露端口

  • cmd和entrypoint,启动

from:

复制代码
# 选择官方镜像(推荐)
FROM node:18-alpine        # 轻量级Node.js
FROM python:3.11-slim      # 轻量级Python
FROM nginx:alpine          # 轻量级Nginx
​
# 指定版本(不要用latest)
FROM ubuntu:20.04          # 明确版本号
FROM python:3.11.4-slim    # 具体小版本

run:

复制代码
# 单一命令
RUN apt-get update
​
# 多个命令合并(减少镜像层数)
RUN apt-get update && apt-get install -y \
    curl \
    git \
    vim \
    && rm -rf /var/lib/apt/lists/*  # 清理缓存
​
# 安装Python包
RUN pip install --no-cache-dir flask gunicorn
​
# 安装Node.js包
RUN npm install --production

COPY vs ADD:

复制代码
# COPY - 简单复制(推荐)
COPY package.json .                 # 复制单个文件
COPY src/ ./src/                    # 复制整个目录
COPY --chown=user:group file.txt .  # 复制并设置权限
​
# ADD - 有特殊功能(谨慎使用)
ADD https://example.com/file.tar.gz /tmp/  # 可以下载URL
ADD file.tar.gz /tmp/              # 会自动解压压缩包

workdir:

复制代码
WORKDIR /app           # 进入/app目录
RUN pwd                # 现在在/app
​
WORKDIR src            # 进入/app/src
RUN pwd                # 现在在/app/src
​
# 相当于:
# cd /app
# cd src

expose:

复制代码
EXPOSE 80              # 暴露80端口(HTTP)
EXPOSE 443             # 暴露443端口(HTTPS)
EXPOSE 3000/tcp        # 指定TCP协议
EXPOSE 3000/udp        # 指定UDP协议
​
# 注意:这只是声明,实际映射要在 docker run 时用 -p 参数

CMD vs ENTRYPOINT:

复制代码
# CMD - 默认启动命令(可以被覆盖)
CMD ["nginx", "-g", "daemon off;"]
CMD ["python", "app.py"]
CMD ["npm", "start"]
​
# ENTRYPOINT - 入口点(不容易被覆盖)
ENTRYPOINT ["java", "-jar"]
​
# 组合使用(常见用法)
ENTRYPOINT ["java", "-jar"]
CMD ["app.jar"]  # 运行时可以覆盖:docker run my-app other.jar

下面是构建一个spring boot应用的docker file:

复制代码
# 构建阶段
FROM maven:3.8.6-openjdk-17 AS builder
​
WORKDIR /build
​
# 先复制pom文件(利用缓存)
COPY pom.xml .
RUN mvn dependency:go-offline
​
# 复制源代码
COPY src ./src
​
# 打包应用
RUN mvn package -DskipTests
​
# 运行阶段
FROM openjdk:17-jdk-slim
​
WORKDIR /app
​
# 创建非root用户
RUN groupadd -r spring && useradd -r -g spring spring
USER spring
​
# 复制打包好的jar文件
COPY --from=builder --chown=spring:spring /build/target/*.jar app.jar
​
# 暴露端口
EXPOSE 8080
​
# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]

打包指令:

复制代码
docker build -t my-custom-nginx:1.0 .
docker run --name energy-saving-platform -p 9999:9999  -d energy-saving-platform:1.0.0

网络

不同服务打包成不同镜像,启动成不同的容器,容器之间通过URL(IP:端口:接口地址)来访问,这样做没问题。但是IP和端口是可能会变动的,这种改动可能会引起我们需要重新去配置DockerFile,重新打包镜像。docker支持通过配置网络实现通过容器名来访问具体服务。所以在多容器通信的场景下,自定义docker网络会是明智之举。

docker支持以下网络模式:

  • bridge

    • 不自定义网络时,会用一个默认的bridge,也可以自定义一个bridge

    • 优点:简单易用,一个物理机端口能运行多个应用,端口资源占用不严重。

    • 缺点:性能不高,毕竟请求要走好几层过滤。

  • host

    • 直接使用物理机的端口

    • 优点:性能高,毕竟请求不需要走好几层,适用于对请求响应速度有高要求的场景,比如物联网、高并发应用

    • 缺点:不安全,一个物理机端口只能运行一个容器,端口资源占用严重。

  • none

    • 相当于是个容器内网,容器内自己玩儿自己的,不能与外部网络通信。

    • 优点缺点不展开,毕竟基本不会用到。

  • overlay

    • 不同物理机的容器可以直接通信

    • 优点:跨机器

    • 缺点:需要Swarm或K8s集群,提升管理成本

配置示例

查看docker网络相关命令

复制代码
# 查看所有网络
docker network ls
​
# 查看网络详细信息
docker network inspect <network-name>
​
# 查看容器网络配置
docker inspect <container-name> | grep -A 20 NetworkSettings
​
# 测试容器间连通性
docker exec <container1> ping <container2>
​
# 查看端口映射
docker port <container-name>

默认bridge

复制代码
# 启动容器,使用默认bridge网络
docker run -d --name webapp1 -p 8080:80 nginx
docker run -d --name webapp2 -p 8081:80 nginx
​
# 查看网络信息
docker network inspect bridge
​
# 测试连通性(需要通过IP访问)
docker exec webapp1 curl http://172.17.0.3  # 需要知道webapp2的IP

自定义bridge

复制代码
# 创建自定义bridge网络
docker network create my-bridge-network
​
# 启动容器并加入自定义网络
docker run -d --name frontend --network my-bridge-network -p 80:80 nginx
docker run -d --name backend --network my-bridge-network -p 3000:3000 node-app
docker run -d --name database --network my-bridge-network -p 3306:3306 mysql:8.0
​
# 现在容器间可以通过名字访问!
docker exec frontend curl http://backend:3000
docker exec backend ping database
​
# 查看网络详情
docker network inspect my-bridge-network

带子网的自定义bridge

复制代码
# 创建指定子网的bridge网络
docker network create \
  --driver bridge \
  --subnet 192.168.100.0/24 \
  --gateway 192.168.100.1 \
  my-custom-subnet
​
# 启动容器并指定IP
docker run -d --name app1 \
  --network my-custom-subnet \
  --ip 192.168.100.10 \
  my-app:latest
​
docker run -d --name app2 \
  --network my-custom-subnet \
  --ip 192.168.100.11 \
  my-app:latest

host

复制代码
# 使用host网络模式
docker run -d --name nginx-host --network host nginx
​
# 此时nginx直接使用主机的80端口
# 访问: http://localhost:80
​
# 查看进程,可以看到直接使用主机网络
netstat -tlnp | grep :80

none就不展示了,没必要。

overlay需要依赖于docker swarm,docker swarm是一个docker官方提供的容器编排工具,允许将多个 Docker 主机组成一个集群,以集群的方式运行和管理容器。

由于技术选型上是用k8s来编排、管理容器集群,所以不展开docker swarm,只需要知道docker的容器编排有轻量级的swarm和重量级的k8s即可。

容器编排(docker compose)

为什么要容器编排

容器编排,即用配置文件编写好容器之间的依赖关系、启动顺序等。docker提供了docker compose来对容器进行编排,用docker-compose.yml来配置,进行容器编排。多镜像部署且需要通信需要写很多命令,假设一个eureka容器和一个应用容器。

没有 Docker Compose 时,两个问题:

  • 整个过程中要手动执行docker build去重新构建镜像,还要去docker run重新拉起应用,还要来回切目录,很麻烦,而且还要顾及启动顺序,先启动注册中心,然后启动应用。命令又长又复杂。

  • IP地址或者端口变化时,要重新修改配置。

使用 Docker Compose 时,只需要:

  1. 在一个 docker-compose.yml 文件中定义这两个服务。执行一条命令:docker compose up。避免了很多手动命令操作。

  2. 通过配置网络,支持服务之间可以通过名称来访问,规避了IP和端口变化带来的问题。

所有步骤都会自动完成。这极大地提高了开发和测试的效率。

没有docker compose的纯手动操作:

用容器的编排脚本,一个脚本就可以搞定,不用上面那么零碎的手动操作。

docker compose使用docker-compose.yml来编排容器,其中要声明和操作的无非就是:

  • 服务 (Services):每个容器就是一个服务

  • 项目 (Project):一组关联服务的集合

  • 网络 (Networks):容器间的通信网络

  • 数据卷 (Volumes):数据持久化

docker-compose.yml结构如下:

复制代码
version: '3.8'  # Compose 文件版本
​
services:   # 定义所有服务
  service1: # 服务1配置
  service2: # 服务2配置
​
networks:   # 自定义网络
volumes:    # 数据卷定义

常用服务配置项

配置项 说明 示例
image 使用现有镜像 image: nginx:alpine
build 从 Dockerfile 构建 build: .
ports 端口映射 ports: - "80:80"
environment 环境变量 environment: - KEY=VALUE
volumes 数据卷挂载 volumes: - ./data:/app/data
networks 加入网络 networks: - app-network
depends_on 依赖关系 depends_on: - db
restart 重启策略 restart: always

docker-compose.yml:

复制代码
services:
  eureka-server:
    build:
      context: ./eurekaServer
      dockerfile: Dockerfile
    ports:
      - "9001:9001"
    environment:
      - JAVA_OPTS=-Xmx512m -Xms256m
    container_name: eureka-server
    networks:
      - microservice-net
    restart: unless-stopped
​
  # 订单服务
  order-service:
    build:
      context: ./orderServer
      dockerfile: Dockerfile
    ports:
      - "9002:9002"
    environment:
      - JAVA_OPTS=-Xmx512m -Xms256m
    container_name: order-service
    networks:
      - microservice-net
    depends_on:
      - eureka-server
    restart: unless-stopped
networks:
  microservice-net:
    driver: bridge

上面的脚本不能保证启动顺序,需要用健康检查来保证启动顺序:

复制代码
services:
  eureka-server:
    build:
      context: ./eurekaServer
      dockerfile: Dockerfile
    ports:
      - "9001:9001"
    environment:
      - JAVA_OPTS=-Xmx512m -Xms256m
    container_name: eureka-server
    networks:
      - microservice-net
    healthcheck:
      test: ["CMD-SHELL", "timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/9001' || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 18  # 总共等待 3 分钟 (10s * 18)
      start_period: 30s
    restart: unless-stopped
​
  order-service:
    build:
      context: ./orderServer
      dockerfile: Dockerfile
    ports:
      - "9002:9002"
    environment:
      - JAVA_OPTS=-Xmx512m -Xms256m
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:9001/eureka/
      - EUREKA_CLIENT_INITIAL-INSTANCE-INFO-REPLICATION_INTERVAL_SECONDS=5
    container_name: order-service
    networks:
      - microservice-net
    depends_on:
      eureka-server:
        condition: service_healthy  # 关键:等待健康状态
    restart: unless-stopped
​
networks:
  microservice-net:
    driver: bridge

启动指令:

复制代码
docker compose up -d
##如果不带-d就会是前台启动
相关推荐
斯普信专业组2 小时前
Kubernetes(K8S)完全详解:从架构设计到云原生实践
云原生·容器·kubernetes
Clownseven2 小时前
2025开发者云服务器评测:AWS, Vercel, Railway该如何选?
运维·服务器·aws
一条懒鱼6663 小时前
Nginx反向代理与缓存功能
运维·nginx
2501_920047033 小时前
docker-容器网络类型
网络·docker·容器
AscendKing3 小时前
Docker 部署 Ollama 详细教程以及镜像高速下载地址
运维·docker·容器
m0_462185113 小时前
大模型部署基础设施搭建 - Docker
docker
world-wide-wait3 小时前
mac安装ubuntu docker
ubuntu·docker
Who_Mr.Lin3 小时前
【docker】常用命令
docker·容器·eureka
努力努力再努力wz3 小时前
【C++进阶系列】:位图和布隆过滤器(附模拟实现的源码)
java·linux·运维·开发语言·数据结构·c++