Docker 安装

# 安装必要软件包
yum install -y yum-utils device-mapper-persistent-data lvm2

# 设置Docker镜像源
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
yum makecache fast

# 安装 docker-ce 版本
yum install docker-ce -y

# 启动Docker服务
systemctl start docker

# 设置Docker随系统启动
systemctl enable docker

Docker 服务命令

# 查看 Docker 版本 
docker --version
docker -v

# 启动Docker服务
systemctl start docker
# 停止Docker服务
systemctl stop docker
# 重启Docker服务
systemctl restart docker
# 查看Docker服务状态
systemctl status docker
# 设置Docker随系统启动
systemctl enable docker

Docker 镜像命令

# 列出所有本地镜像,-a 包括中间镜像
docker images

# 搜索镜像
docker search 镜像名称

# 拉取镜像
docker pull 镜像名称:版本号

# 删除镜像,删除需要先删除相关容器,-f 可以强制删除,容器ID可以只输入前几位
docker rmi 镜像ID或镜像名:版本号

# 加载自定义镜像(加载自己的镜像文件.tar)
docker load -i 镜像文件名称.tar

Docker 容器命令

# 创建并启动一个新的容器(创建时需要设置很多配置,如端口号,挂载目录等等)
# OPTIONS:
#	-d 后台运行
#	-p 端口映射
#   -v 本地目录:容器内目录  (挂载目录)
#   -e 设置参数
#	--name 名称 容器命名 
#   --restart=always 随docker服务启动
#   --network my01 指定容器所属的网络,没有my01网络会自动创建
docker run [OPTIONS] 镜像名[:TAG] [COMMAND] [ARG...]

# 容器挂载需要注意事项
# 挂载目录只能在创建容器的时候使用 -v 进行挂载
# 挂载目录语句格式为:-v 本地目录:容器内目录
# 以/或./开头是使用本地目录挂载,如: -v /data:/var/lib/data
# 如果直接以名称开头则会被识别为数据卷而非本地目录 如:-v data:/var/lib/data
# 数据卷默认存储位置为宿主机的/var/lib/docker/volumes下,docker run 创建时,没有数据卷会自动创建
# 有一部分容器在创建时,如果没有进行挂载,会自动创建数据卷对容器的关键数据目录进行挂载,如mysql
# 查看容器挂载目录可以使用docker inspect 容器ID或容器名 ,查询容器详细信息中的 Mounts
docker run -v 本地目录:容器内目录 mysql

# 列出当前运行的容器,-a 列出所有容器
docker ps

# 查看容器详情信息
docker inspect 容器ID或容器名

# 启动已存在的容器
docker start 容器ID或容器名

# 停止运行中的容器
docker stop 容器ID或容器名

# 重启容器
docker restart 容器ID或容器名

# 拷贝容器中的文件出来
docker cp 容器ID或名称:目标路径 源文件或目录 

# 拷贝文件到容器中去
docker cp 源文件或目录 容器ID或名称:目标路径

# 进入容器执行命令
docker exec -it 容器ID或容器名 /bin/bash

# 删除容器
docker rm 容器ID或容器名

# 设置已运行的容器随docker服务启动而自启
docker update --restart=always 容器ID或容器名

Docker Network 网络

默认网络docker0

有时会出现一种需求,就是容器之间的互相访问,所以需要了解Docker容器是如何分配网络的。

系统在安装后,会创建一个虚拟网卡叫docker0

以CentOS7.9为例,使用 ip addr命令查看网络

ens33为宿主机网络

docker0就是安装docker后自动创建的虚拟网卡

IP为 172.17.0.1/16 (16的意思为前16为不可改变,ip转二进制,一组是8位,所以是172.17不可改变)

创建容器后容器的IP会自动非配,如172.17.0.2,172.17.0.3,它们都以bridge(桥接)的方式链接到Docker的虚拟网卡上。

容器之间使用IP即可互相访问,但是使用默认网络(docker0)会有一个问题,就是每次容器重启后分配的IP可能会不一样。

比如MySQL容器的IP是172.17.0.2,下载重启后,.0.2被Redis容器占用,那么MySQL就会分配到172.17.0.3,这样就会导致容器与容器之间连接失败。

自定义网络

加入自定义网络的容器可以通过容器名互相访问,这样就解决了自动分配IP发生变化的问题。

在创建容器时,可以使用 --network 网络名,来指定容器所属的自定义网络,网络名不存在时会自动创建。

之后就需要使用docker netwrok命令来对容器的网络进行操作了。

# 创建一个新的自定义网络
docker network create 网络名

# 列出所有的网络
docker network ls

# 显示一个或多个网络的详细信息
docker network inspect 网络名

# 删除一个或多个网络
docker network rm 网络名

# 将一个或多个容器连接到网络
docker network connect 网络名 容器名或容器ID

# 将一个或多个容器从网络中断开连接
docker network disconnect 网络名 容器名或容器ID

# 删除所有未使用的网络
docker network prune

镜像结构

镜像分层

在拉取镜像时,会发现有这么一段信息

这代表着一个镜像结构有多个分层镜像组成。

这些分层镜像分为三类

  • 入口( Entrypoint )

镜像运行的入口,一般是程序启动的脚本和参数。

  • 层 ( Layer )

添加安装包、依赖、配置等,如拷贝jar包,安装jar包,配置环境变量等等。

每次操作都会形成新的一层。

  • 基础镜像 ( BaseImage )

应用依赖的系统函数库、环境、配置、文件等。

为什么要分层?

这种设计方式,加快了用户的下载速度。

用户拉取镜像后,镜像的分层镜像都存储在本地系统上,当用户拉取新镜像时,如果使用到本地系统中的分层镜像,这一层即可不用下载直接拉取完成。

以 java 项目举例

镜像由 ubuntu:16.04 为基础镜像

拷贝 jar 包为层镜像

安装 JDK8 和配置环境变量为层镜像

运行 jar 包命令为入口镜像

当要部署其他项目时,因为本地系统中已经存在之前部署的镜像,除了拷贝 jar 包这一层镜像需要重新生成,其他的都会立即完成。

Dockerfile

Dockerfile 是用于自动化构建 Docker 镜像的文本文件,它包含了一系列用于定制镜像的指令。

常见指令

指令

说明

示例

FROM

指定基础镜像

FROM ubuntu:20.04

LABEL

为镜像添加元数据标签

示例中指定maintainer(作者)与version

LABEL maintainer="yourname@example.com" version="1.0"

ENV

设置环境变量

ENV NODE_ENV=production

WORKDIR

设置工作目录,之后的 RUN, CMD, COPY, ADD 等指令将在这个目录下执行

注意:如果指定工作目录,那么默认目录为 / ,即系统根目录

WORKDIR /app

COPY

拷贝本地文件到镜像指定的目录

COPY package.json /app/

ADD

类似于 COPY,但能支持自动解压和从 URL 下载文件

ADD https://example.com/archive.tar.gz /app/

RUN

执行Linux的shell命令

RUN apt-get update && apt-get install -y nginx

CMD

定义容器启动时默认执行的命令及参数。可以被 docker run 的命令行参数覆盖

CMD ["npm", "start"]

EXPOSE

指定容器运行时监听的端口

注意:这里只是说明,给使用者看的,创建容器时还是需要 -p 来开放端口

EXPOSE 8080

ENTRYPOINT

镜像中应用的启动命令,容器运行时调用

ENTRYPOINT ["python", "-m"]

VOLUME

创建一个挂载点,用于持久化数据或与其他容器共享数据

VOLUME /var/lib/mysql

指令的使用

以下使用 ubuntu:16.04为基础镜像,安装jdk,拷贝jar,运行java项目

# 基础镜像
FROM ubuntu:16.04
# 配置环境变量
ENV JAVA_DIR=/usr/local
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./java-demo.jar /java-demo.jar
# 安装JDK
RUN cd $JAVA_DIR \ && tar -xf ./jdk8.tar.gz \
&& mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
#入口.java项目的启动命令
ENTRYPOINT ["java", "-jar", "java-demo.jar"]

上面是为了演示指令的使用,实际运行java项目可以使用jdk8为基础镜像来运行

# 基础镜像
FROM  openjdk:8-jre
# 拷贝jar包
COPY ./java-demo.jar /java-demo.jar
#入口.java项目的启动命令
ENTRYPOINT ["java", "-jar", "java-demo.jar"]

运行Dockerfile构建镜像

# 语句格式  docker built -t 镜像名:镜像版本号 Dockerfile所在目录
# -t :给镜像起名,格式为repository:tag,不指定tag时,默认为latest
#  . :是指定Dockerfile的所在目录,如果在当前目录,则指定为"." 
docker build -t myImage:1.0 .

docker-compose工具

Docker Compose通过一个单独的docker-compose.yaml 模板文件(YAML格式)来定义一组相关联的应用容器,帮助我们实现多个相关联的Docker容器的快速部署。

安装

在 Linux 系统上安装

# 这里 v2.12.2 是示例版本号,请替换为实际要下载的版本。
sudo curl -L "https://github.com/docker/compose/releases/download/v2.12.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 设置执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 验证安装
docker-compose --version

模板文件

简单Docker run命令与docker-compose.yaml文件对比

# docker run 创建mysql命令
docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
-v /usr/local/mysql/conf:/etc/mysql/conf.d \
-v /usr/local/mysql/logs:/logs \
-v /usr/local/mysql/data:/var/lib/mysql \
--restart=always \
--network my-network \
mysql:5.7

# 打开docker-compose.yaml文件
vi docker-compose.yaml

# docker-compose.yaml内容
# 指定 Docker Compose 的版本,这里是 3.8 版本。
version: "3.8"
services:
  # 这里的mysql为这个services的名称,如果不指定container_name就会是容器默认名称
  mysql:
    # 这里的mysql为容器名称,docker run --name mysql
    container_name: mysql
	# 这里为镜像名
    image: musql5.7
	# 开放端口,这里为了演示多个端口开放,实际mysql开放3306即可
    ports:
      - "3306:3306"
      - "3307:3307"
	# 指定参数 ,docker run -e
	environment:
      MYSQL_ROOT_PASSWORD=123456
      TZ=Asia/Shanghai
	# 目录挂载,docker run -v
    volumes:
      - /usr/local/mysql/conf:/etc/mysql/conf.d
      - /usr/local/mysql/logs:/logs
      - /usr/local/mysql/data:/var/lib/mysql
	networks:
      - my-networks

复杂模板

# 指定 Docker Compose 的版本,这里是 3.x 版本。
version: "3"

services:
# 容器1: halo, 镜像存在于docker hub 上
  halo:
    image: halohub/halo:2.15
	# 当服务因错误停止时,尝试重启最多 3 次。
    restart: on-failure:3
	# Halo 服务依赖于 halodb 服务,并且只有当 halodb 服务健康时才启动。
    depends_on:
      halodb:
        condition: service_healthy
	# 将 Halo 服务连接到名为 halo_network 的网络。
    networks:
      halo_network:
	# 映射本地的 ./halo2 目录到容器内的 /root/.halo2,用于持久化数据。
    volumes:
      - ./halo2:/root/.halo2
    ports:
      - "8090:8090"
	# 设置健康检查,每 30 秒检查一次 Halo 应用的健康状态,初始等待 30 秒,超时时间 5 秒,失败后重试 5 次。
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 30s
	# 设置启动 Halo 应用时使用的命令行参数,包括数据库连接信息等。
    command:
      - --spring.r2dbc.url=r2dbc:pool:mysql://halodb:3306/halo
      - --spring.r2dbc.username=root
      # MySQL 的密码,请保证与下方 MYSQL_ROOT_PASSWORD 的变量值一致。
      - --spring.r2dbc.password=o#DwN&JSa56
      - --spring.sql.init.platform=mysql
      # 外部访问地址,请根据实际需要修改
      - --halo.external-url=http://localhost:8090/

# 容器2:mysql, 镜像存在于docker hub 上
  halodb:
    image: mysql:8.1.0
    restart: on-failure:3
	# 类似 Halo 服务,设置重启策略和网络连接。
    networks:
      halo_network:
	# MySQL 启动命令,设置字符集、认证插件等。
    command: 
      - --default-authentication-plugin=caching_sha2_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --explicit_defaults_for_timestamp=true
    volumes:
      - ./mysql:/var/lib/mysql
      - ./mysqlBackup:/data/mysqlBackup
    ports:
      - "3306:3306"
	# 设置 MySQL 的健康检查。
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
      interval: 3s
      retries: 5
      start_period: 30s
	# 设置 MySQL 的 root 密码和默认数据库名。
    environment:
      # 请修改此密码,并对应修改上方 Halo 服务的 SPRING_R2DBC_PASSWORD 变量值
      - MYSQL_ROOT_PASSWORD=o#DwN&JSa56
      - MYSQL_DATABASE=halo

# 容器3:自己的java项目,镜像需要制作
  my-project:
    container_name: my-project
	# 构建镜像方式为dockerfile
	# 注意这里的context: ./app 相对路径的起点是docker-compose.yaml的位置
	# ./app目录下要有dockerfile文件,然后会使用里面的指令构建镜像
	# 如果dockerfile就在当前目录使用"."即可
    build:
      context: ./app
      dockerfile: dockerfile
    ports:
      - "8080:8080"
    depends_on:
      halodb:
        condition: service_healthy
    networks:
      halo_network:

# 网络配置,定义一个名为 halo_network 的网络,供服务间通信使用。
networks:
  halo_network:

命令

# 查看docker-compose版本信息
docker-compose version

# 以下命令要在docker-compose.yaml文件所在目录使用

# 检查 docker-compose.yml 文件的语法,并显示解析后的配置。
docker-compose config

# 构建启动所有容器
docker-compose up -d
# 构建启动某个容器
docker-compose up -d 服务名

# 停止并删除所有容器,网络,镜像等相关资源
docker-compose down

# 显示项目中所有服务的容器状态。
docker-compose ps

# 进入到容器中
docker-compose exec 服务名 /bin/bash

# 查看服务容器的日志输出。
docker-compose logs -f 服务名
# 查看容器的实时日志(从最后10行开始)
docker-compose logs --tail 10 -f 服务名

# 列出所有镜像
docker-compse images

# 构建服务的镜像(可以用于重新构建镜像)
docker-compose build 服务名
# 不带缓存的构建
docker-compose build --no-cache 服务名

# 暂停容器
docker-compose pause 服务名
# 恢复容器
docker-compose unpause 服务名

# 重启项目中的容器
docker-compose restart
# 重启项目中的某个容器
docker-compose restart 服务名

# 停止项目中的容器
docker-compose stop
# 停止项目中的某个容器
docker-compose stop 服务名

# 启动已经存在的容器。
docker-compose start
# 启动已经存在的某个容器。
docker-compose start 服务名

# 删除已经停止的容器。
docker-compose rm
# 删除已经停止的某个容器。
docker-compose rm 服务名

# 显示服务容器的进程信息。
docker-compose top