一、配置docker源
1.1 安装
# 安装相关依赖
yum install -y yum-utils
# 下载官方的docker yum源文件
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 替换源地址
sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# 安装docker-ce
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
docker version
1.2 配置镜像加速
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://docker.1ms.run"]
}
EOF
重新加载
systemctl daemon-reload
systemctl restart docker
二、第一个docker容器实例
C/S架构
docker服务端:dockerd
docker客户端:下载镜像、运行容器…
镜像 | Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。它也相当于是一个root文件系统。比如官方镜像 centos:7 就包含了完整的一套 centos:7 最小系统的 root 文件系统。 |
容器 | Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台 可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序 |
仓库 | 仓库(Repository)是集中存放镜像文件的场所,仓库分为公开仓库(Public)和私有仓库(Private)两种形式 |
# -d 后台运行 -p 端口映射 --name 容器名字 nginx 镜像名字
docker run -d -p 80:80 --name "first_nginx" nginx
三、镜像管理
Docker镜像加载原理:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统叫UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
docker 家目录 | /var/lib/docker |
---|---|
docker search | 搜索镜像 |
docker pull | 拉取镜像 |
docker push | 推送镜像 |
docker load | 导入镜像 docker load -i docker_centos7.tar.gz |
docker save | 导出镜像 docker save centos:7 -o docker_centos7.tar.gz |
docker images | 查看镜像 |
docker image inspect nginx | 查看镜像的详细信息,输出为json |
docker rmi | 删除镜像 |
docker tag | 给镜像打标签 docker tag a830707172e8 nginx:1.0 |
docker build | 结合Dockerfile自定义镜像 |
docker inspect | 查看镜像信息 |
四、容器管理
docker ps | 查看容器列表 -a 查看所有容器 -q 只显示容器id |
docker run | 创建并运行容器 -i 进入交互模式 -t 分配一个终端 -d 后台运行 -v 挂载容器卷 --rm 容器退出的时候,自动删除 –restart=always 自动重启 unless-stopped 只在容器关闭、停止的时候重启 on-failure 只在失败的时候重启 默认不重启 |
docker volume create | 创建数据卷空间,只关注容器中的数据不丢,创建后的数据卷空间存放在/var/lib/docker/volumes/下 |
docker logs | nginx容器的日志默认是输出到docker标准输出和标准错误输出,而不是存放在文件中,可以通过docker logs xxx查看日志 |
docker export docker import | 导出容器信息为tar包 从tar包将容器导入成镜像 |
docker create | 创建容器 |
docker start | 启动容器 |
docker stop | 停止容器 |
docker restart | 重启容器 |
docker kill | 强制停止容器 |
docker rm | 删除容器 |
docker exec | 进入正在运行的容器(分配一个新终端) docker exec -it 容器id/容器名字 /bin/bash |
docker attach | 进入正在运行的容器(共用相同的终端) |
docker cp | 宿主机与docker容器之间传输数据 上传:docker cp 宿主机路径 容器名字:容器路径 下载:docker cp 容器名字:容器路径 宿主机路径 |
docker stats docker top docker inspect | 查看容器状态、信息 |
docker commit | 将容器提交成新镜像 docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要创建的目标镜像名:[标签名] |
五、dockerfile
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
- 编写Dockerfile文件
- docker build -t “镜像名” . 构建镜像
- docker run 镜像运行容器实例
5.1 Docker执行Dockerfile的大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
5.2 常用保留字指令
FROM | 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是FROM | 尽量指定具体版本 |
LABEL | 以键值对的形式用于指定容器的属性信息,作者,个人联系方式,邮件等等 | |
ENV | 用来在构建镜像过程中设置环境变量 | ENV <key> <value> |
RUN | 容器构建时需要运行的命令,是在 docker build时运行 | Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大 RUN yum -y install wget \ && tar -xvf redis.tar.gz |
ADD | 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包 | 拷贝压缩包 |
COPY | 将文件或目录复制到镜像中,不会解压压缩包 | COPY [–chown=<user>:<group>] <源路径1>… <目标路径> 用于拷贝文件或目录,同样需求下,官方推荐使用 COPY |
WORKDIR | 指定在创建容器后,终端默认登陆进来的工作目录 | 一般用于配合ADD,COPY需要书写容器中路径指令,Dockerfile中使用相对路径操作容器 |
VOLUMN | 挂载数据卷 | 在docker run的时候用-v即可 |
结尾部分书写的内容 | ||
EXPOSE | 当前容器对外暴露出的端口 | 暴露出的端口可以被-P识别,-P 宿主机的随机端口映射到容器的指定端口 |
CMD | 在docker run 时运行,指定一个容器启动时要运行的命令。Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换 | 大部分时候使用CMD CMD [“命令”,“参数01”,“参数02”] CMD [“nginx”,“-g”,“daemon off;”] CMD [“catalina.sh”,“run”] |
ENTRYPOINT | 也是用来指定一个容器启动时要运行的命令,类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序,如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效 | ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令 |
5.3 多阶段提交
一个Dockerfile有多个FROM
应用场景:压缩镜像的大小,镜像分层次架构,适用于编译安装/构建场合,先通过中间镜像进行编译,编程结果存放到新的镜像中。
FROM ubuntu:20.04 AS base
…
FROM ubuntu:20.04
COPY --from=base /app/ /app/
5.4 示例
# 阶段 1: 构建阶段
# 定义构建参数(可设置默认值)
ARG MAVEN_VERSION=3.9
ARG JDK_VERSION=17
FROM maven:${MAVEN_VERSION}-eclipse-temurin-${JDK_VERSION}-alpine AS builder
# 声明构建期可访问的环境变量
ARG BUILD_NUMBER=0
ARG SKIP_TEST=true
ENV BUILD_NUMBER=${BUILD_NUMBER}
WORKDIR /app
COPY pom.xml .
# 利用缓存提前下载依赖
RUN mvn dependency:go-offline -B
COPY src ./src
# 带参数构建
RUN mvn package -DskipTests=${SKIP_TEST}
# 阶段 2: 运行时阶段 - 使用最小化 JRE 镜像
# 阶段 2: 运行时阶段
# 覆盖基础镜像版本变量
ARG JDK_VERSION=17
FROM eclipse-temurin:${JDK_VERSION}-jre-alpine
# 声明运行时环境变量
ARG APP_VERSION=1.0.0
ENV APP_VERSION=${APP_VERSION} \
TZ=Asia/Shanghai
# 非 root 用户配置
ARG APP_USER=appuser
ARG APP_UID=1001
RUN addgroup -g ${APP_UID} ${APP_USER} && \
adduser -u ${APP_UID} -G ${APP_USER} -D ${APP_USER}
WORKDIR /app
COPY --from=builder --chown=${APP_USER}:${APP_USER} /app/target/*.jar ./app.jar
# 优化 JVM 参数(根据需求调整)
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
# 健康检查(Spring Boot Actuator 端点)
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/actuator/health || exit 1
USER ${APP_USER}
# 暴露端口(根据实际应用端口修改)
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
六、docker网络
6.1 概述
docker启动后,会产生一个名为docker0的虚拟网桥,默认创建三大网络模式,用于容器间互联和通信以及端口映射,容器IP变动时可以通过服务名直接网络通信而不受影响
6.2 常用基本命令
查看网络 docker network ls
查看网络源数据 docker network inspact 网络名称
删除网络 docker network rm 网络名称
6.3 网络模式
bridge模式 | 使用–network bridge指定,默认使用docker0 | Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信 宿主机会有个veth对应容器的eth0 |
host模式 | 使用–network host指定 | 直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换 |
none模式 | 使用–network none指定 | 在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo。需要我们自己为Docker容器添加网卡、配置IP等 |
container模式 | 使用–network container:NAME或者容器ID指定 | 新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。 |
自定义网络模式 | 使用–network 网络名 指定 | 自定义网络本身就维护好了主机名和ip的对应关系,也就是ip和服务名都能通信 |
6.4 同一台宿主机的容器间通信
通信方式 | 实现方法 | 优点 | 缺点 |
---|---|---|---|
默认 Bridge 网络 | 容器通过 IP 或名称通信 | 简单易用 | 默认不支持容器名称通信 |
自定义网络 | 创建自定义网络,容器通过名称通信 | 支持容器名称通信,网络隔离性好 | 需要手动创建网络 |
–link(不推荐) | 使用 --link 连接容器 | 早期支持容器名称通信 | 功能有限,已弃用 |
Host 网络 | 容器共享宿主机网络栈 | 直接使用宿主机网络 | 安全性低,可能导致端口冲突 |
Docker Compose | 自动创建网络,容器通过服务名通信 | 简化多容器管理,支持服务名称通信 | 需要编写 docker-compose.yml 文件 |
共享数据卷 | 容器通过共享文件系统通信 | 适合共享数据场景 | 仅适用于文件系统通信 |
七、docker-compose
7.1 docker-compose与docker compose
原文链接:https://blog.csdn.net/u010066597/article/details/137753590
Docker Compose 有两种使用方式,分别是 docker-compose 和 docker compose。这两种方式之间存在一些差异:
集成程度:
docker-compose 是一个独立的工具,需要单独安装和配置。
docker compose 是 Docker 命令行工具的一部分,更加紧密地集成在 Docker 生态中。
兼容性:
docker-compose 可以在任何支持 Docker 的系统上使用,不受 Docker 版本的限制。
docker compose 需要 Docker 19.03 及以上版本才能使用。
总的来说,docker compose 是 Docker 官方推荐的新用法,它提供了更好的集成和用户体验。但如果你需要在较旧的 Docker 版本上使用 Docker Compose,或者需要更多的灵活性,那么使用 docker-compose 命令可能更合适。
7.2 概述
dockerfile是对镜像进行管理
docker compose是对容器进行管理
单机容器编排工具:docker compose
容器集群管理:
ansible+dockerfile+docker compose
docker swarm
k8s
7.3 常用基本命令
docker-compose | 这个命令包含了docker container和docker image 命令 |
---|---|
-h | 查看帮助 |
up -d | 启动所有docker-compose服务并后台运行 |
down | 停止并删除容器、网络、卷、镜像 |
exec yml里面的服务id | 进入容器示例内部 |
ps | 展示当前docker-compose编排过的所有运行的容器 |
top | 展示当前docker-compose编排过的容器进程 |
logs yml里面的服务id | 查看容器日志 |
config -q | 检查配置 有问题才输出 |
restart|start|stop | 重启服务|启动服务|停止服务 |
run | 运行容器 |
images | 查看镜像 |
7.4 示例
version: '3.8'
# 定义共享网络(实现服务隔离)
networks:
app_network:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
# 集中管理环境变量
x-environment: &common_env
TZ: Asia/Shanghai
LANG: C.UTF-8
# 共享配置扩展点
x-logging: &default_logging
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
services:
# 后端服务(Spring Boot 示例)
backend:
image: your-registry/backend:${TAG:-latest}
build:
context: ./backend
dockerfile: Dockerfile
args:
- BUILD_NUMBER=${BUILD_NUMBER:-0}
environment:
<<: *common_env
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/app_db
SPRING_REDIS_HOST: redis
SPRING_PROFILES_ACTIVE: prod
networks:
- app_network
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
interval: 30s
timeout: 5s
retries: 3
logging: *default_logging
# 数据库服务(PostgreSQL)
db:
image: postgres:15-alpine
networks:
- app_network
environment:
<<: *common_env
POSTGRES_USER: app_user
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app_user"]
interval: 10s
timeout: 5s
retries: 5
logging: *default_logging
# Redis 缓存服务
redis:
image: redis:7-alpine
networks:
- app_network
command: redis-server --save 60 1 --loglevel warning
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
logging: *default_logging
# 前端服务(Nginx + React 示例)
frontend:
image: your-registry/frontend:${TAG:-latest}
build:
context: ./frontend
dockerfile: Dockerfile
networks:
- app_network
depends_on:
backend:
condition: service_healthy
environment:
<<: *common_env
API_BASE_URL: http://backend:8080/api
ports:
- "80:80"
logging: *default_logging
# 敏感数据管理
secrets:
db_password:
file: ./secrets/db_password.txt
# 持久化存储定义
volumes:
pg_data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/pg_data
redis_data:
driver: local
driver_opts:
type: none
o: bind
device: ./data/redis_data