当前位置: 首页 > news >正文

Docker——使用docker工具管理软件/组件的运行,镜像、容器、数据卷的基本概念,常用指令,使用docker搭建Java微服务运行环境

Docker——使用docker工具管理软件/组件的运行,镜像、容器、数据卷的基本概念,常用指令,使用docker搭建Java微服务运行环境

  • 一、docker的安装和卸载
    • 1.卸载
    • 2.安装
    • 3. 导入已有的镜像文件
  • 二、docker概念
    • 1.镜像和容器
    • 2.镜像和容器的关系
    • 3.镜像的唯一标识
    • 4.中央仓库和下载镜像
  • 三、使用docker
    • 1.镜像相关命令
    • 2.容器相关命令
    • 3.数据卷相关命令
  • 四、高级
    • 1.Docker Compose
      • 1-1 安装与卸载
      • 1-2 命令
      • 1-3 docker-compose.yml 文件
      • 1-4 docker-compose 中自动创建数据卷
    • 2.Dockerfile
      • 2-1 语法指令
      • 2-2 基于 openjdk 构建 Java 项目(最简版)
      • 2-3 基于 openjdk 构建 Java 项目(改进版)
      • 2-4 基于openjre构建的Java微服务项目

一、docker的安装和卸载

1.卸载

# 查看
yum list installed|grep docker
# 输入查看到的docker名称卸载
yum remove [docker名称]
# 验证,查看docker版本
docker -v

2.安装

第 1 步:关闭防火墙

开发环境中,我们通常会关闭开发服务器的防火墙。

systemctl status firewalld        # 查看防火墙状态
systemctl disable firewalld --now # 禁用,且立即生效

第 2 步:卸载旧版本

较旧的 Docker 版本称为 dockerdocker-engine 。如果已安装这些程序,请卸载它们以及相关的依赖项。

yum remove docker           \
    docker-client           \
    docker-client-latest    \
    docker-common           \
    docker-latest           \
    docker-latest-logrotate \
    docker-logrotate        \
    docker-engine

第 3 步:添加 Docker 官方软件源

cat > /etc/yum.repos.d/docker-ce.repo << EOF
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://repo.huaweicloud.com/docker-ce/linux/centos/\$releasever/\$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://repo.huaweicloud.com/docker-ce/linux/centos/gpg
EOF

# 更新 yum 软件源的清单
yum makecache

第 4 步:验证软件源配置

查看所有仓库中所有 docker 版本:

yum list docker-ce --showduplicates | sort -r

如果出现一大堆的 docker-ce 信息则表示 Docker 官方软件源配置正确。

第 5 步:下载 Docker 并安装

# 安装默认版本(也就是最新版)
yum install -y docker-ce

第 6 步:配置 Docker Server 开机启动

# 加入开机启动项,且立刻生效(即,现在就启动,而不用等下次系统重启)
systemctl enable docker --now

# 查看状态
systemctl status docker

会出现类似如下结果:

Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.

第 7 步:验证安装是否成功

输入 docker version 命令,会出现类似如下内容:

Client: Docker Engine - Community
  Version:          20.10.12
  ...

Server: Docker Engine - Community
Engine:
  Version:          20.10.12
  ...

有 Client 和 Server 两部分表示 docker server 安装并启动都成功了。

第 8 步:配置国内 docker hub 镜像服务器

由于 docker hub 的中央镜像仓库在国外,因此有时我们连接 docker hub 从中下载镜像速度会很感人,因此,我们需要配置国内的镜像网址,从国内现在镜像文件。

补充 国内的镜像本质上就是 docker hub 中央仓库在国内的一份缓存/备份。

  • 创建并编辑 docker 配置文件

    mkdir -p /etc/docker
    
    cat > /etc/docker/daemon.json << EOF
    {
      "registry-mirrors": [
        "https://docker.mirrors.ustc.edu.cn",
        "https://registry.docker-cn.com"
      ]
    }
    EOF
    

    该配置文件配置了两个镜像,一个是 docker 官方在中国境内的官方镜像,一个是中科大维护的一个镜像。

  • 重新启动 docker 服务

    systemctl restart docker
    

    查看修改结果:

    docker info
    

    会有如下内容( 则表示配置成功并生效 ):

    ...
    Registry Mirrors:
      https://docker.mirrors.ustc.edu.cn/
      https://registry.docker-cn.com/
    ...
    

    第 9 步:验证连接 docker hub 网络镜像仓库

    输入 docker search -f is-official=true mysql 命令,会出现类似如下结果:

    NAME     DESCRIPTION                                     STARS  OFFICIAL ...
    mysql    MySQL is a widely used, open-source relation…   8819   [OK]     ...
    mariadb  MariaDB is a community-developed fork of MyS…   3102   [OK]     ...
    percona  Percona Server is a fork of the MySQL relati…   459    [OK]     ...
    

3. 导入已有的镜像文件

考虑到有些场景下的联网的不方便,docker 提供了将已下载的 images 打包导出,再在别处导入的功能。

  • 导出镜像:docker save 命令

    # 语法:
    # docker save <repository>:<tag> -o <repository>.tar
    
    # 例如:
    docker save mysql:8.0.16 -o mysql-8.0.16.tar
    
  • 导入镜像:docker load 命令

    # 语法:
    # docker load -i <repository>.tar
    
    # 例如:
    docker load -i mysql-8.0.16.tar
    

二、docker概念

1.镜像和容器

镜像
Docker 将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起。这个"在一起"的文件就称为镜像。
这个"在一起"的文件中,"一个应用程序"是核心、是关键,其它所有的一切都是为了它的( 未来的 )运行而服务的。

容器
镜像中的应用程序运行后形成的进程就是容器,只是 Docker 会给容器做隔离,对外不可见。
简单来说,Docker 容器就是伪装成虚拟机的一个进程。这个进程运行的代码就是创建这个容器时所使用的镜像中的那个应用程序。

2.镜像和容器的关系

简单来说,我们直接面对、使用的是容器。
但是,镜像是容器的"模板",容器"来源"自镜像。
所以,我们要先"搞"到镜像,再通过镜像"搞"到容器,然后才算是将 Docker "用"了起来。

提示
这就有点像类和对象的关系。
我们要用的是对象,但是我们需要先搞到类。有了类之后,才能通过类来 new 出对象。

3.镜像的唯一标识

在 Docker 世界中中,为了分辨"这个这个镜像"和"那个那个镜像"谁是谁,就给每一个镜像起了个名字,所有的镜像的完整的名称主要分为三部分:namespace / repository : tag 。例如:

library/nginx:stable
library/nginx:1.18.0
要素说明
namespace镜像的名字空间,用于区别同名镜像。 通常,namespace 是镜像的作者(个人或组织)的名字。
Repository镜像的简单名称。日常口头交流时,一般都用它。 通常会采用镜像中"那个"要运行的应用程序命名。
tag镜像的标签 一般是镜像的版本号。

重点
对于任意一个镜像而言,上述三者的组合一定是、必须是唯一的。

另外,每个镜像都有一个 ID( 一个 64 位的十六进制字符串 ),它也是唯一的。

4.中央仓库和下载镜像

由于没有镜像就无法创建容器,因此,在正式使用 Docker 时,第一步就是要确保你手里有你想要的镜像。逻辑上,这个镜像中应该包含着你所要使用的那个应用程序,例如,MySQL 或者 Redis 。

从中央仓库下载镜像,是你"搞"到镜像的最常见方式。

DockerHub 是一个 Docker 官方提供的的 Docker 镜像的托管平台。类似于 mvnrepository 网站。

网址:https://hub.docker.com/

三、使用docker

1.镜像相关命令

作用命令举例
查找镜像docker searchdocker search mysql
下载镜像docker pulldocker pull library/nginx:latest
查看本地镜像docker imagesdocker images
删除本地镜像docker rmidocker rmi -f mysql:8.0
导出镜像docker savedocker save mysql:8.0.16 -o mysql-8.0.16.tar
导入镜像docker loaddocker load -i mysql-8.0.16.tar

1-1 查找镜像

# 查询结果包含官方和非官方镜像信息
docker search mysql

# -f is-official=true 表示仅显示官方镜像信息
docker search -f is-official=true mysql

显示出来的搜索结果中包含了镜像的如下信息:

NAME: 镜像的名称
DESCRIPTION: 镜像的简单描述
STARTS: 镜像在的点赞数
OFFICIAL: 镜像是否为 Docker 官方提供( 建议使用官方提供的镜像 )
AUTOMATED: 镜像是否使用了自动构建

1-2 查看本地镜像

docker images
# 当本地镜像较多时,还可以使用通配符过滤出符合条件的镜像。例如:
docker images ph*
REPOSITORY: 镜像的名称。会一并显示它的 Namespace
TAG: 镜像的标签
IMAGE ID: 镜像的 ID。一个长 64 位的十六进制字符串( SHA256 算法的运算结果 )
CREATE: 镜像的创建时间
SIZE: 镜像所占用的硬盘空间( 包括被共享的镜像层的大小 )

1-3 下载镜像

docker pull nginx
# 等价于
docker pull library/nginx:latest

注意:
镜像三要素,如果省略了 namespace ,那么就是默认 library;如果省略了 tag ,那么就是默认 latest 。

所以,这就是为什么 nginx 等价 library/nginx:latest 。

1-4 删除本地镜像

默认情况下,如果至少还存在一个容器使用该镜像,那么该镜像无法删除。

-f 选项表示停止容器,并强制删除该镜像。不过并不推荐强制删除。

如果一个镜像中含有某些与其它镜像共享的镜像层,这些被共享的镜像层仍会被保留下来,

只有未被其它镜像使用的层会被删除。

# 在删除镜像时,需要指定镜像名称或镜像 ID
docker rmi -f mysql:8.0
# 或
docker rmi -f c20987f18b13

1-5 导出镜像

# 语法:
# docker save <repository>:<tag> -o <repository>.tar

# 例如:
docker save mysql:8.0.16 -o mysql-8.0.16.tar
# 另外,docker save 命令支持同时导出多个镜像,这多个镜像被打进了一个 .tar 文件中。
docker save -o image.tar ubuntu:lasted centos:latest

1-6 导入镜像

# 语法:
# docker load -i <repository>.tar
  
# 例如:
docker load -i mysql-8.0.16.tar

2.容器相关命令

作用命令举例
创建容器并运行docker rundocker run -d -p 80:80 --name test nginx
查看当前运行的所有容器docker psdocker ps -a
停止指定的容器docker stopdocker stop test
启动容器docker startdocker start test
删除容器docker rm -fdocker rm -f $(docker ps -aq
进入容器docker exec -itdocker exec -it <容器名> /bin/bash
退出容器exitexit
查看容器日志docker logsdocker logs <容器名>

2-1 创建+运行

# docker run ... --name <容器名> <镜像名>
# 这里的 nginx 镜像等价于 library/nginx:stable ,它省略了 namespace 和 tag 
docker run --rm  -d -p 80:80 --name test nginx

选项说明:

-d: 表示容器启动后在后台运行
-p 80:80: 表示将主机的 80 端口和容器的 80 端口『对接』。即,宿主机从 80 端口收到的数据,由系统送到 docker 的 80 端口。
--name test: 表示所创建的容器的名字为 test 。
nginx: 表示以 nginx镜像为基础创建容器。
--rm: 当容器停止时\无法启动时就自动删除容器。

2-2 查看

# 仅显示 Up 状态的容器
docker ps

# 显示所有状态容器
docker ps -a

选项说明:

CONTAINER ID: 容器的唯一性标识
IMAGE: 容器所使用的镜像
COMMAND: 容器启动时运行的命令( 即,容器中的主程序 )
CREATED: 容器的创建时间
STATUS: 容器的运行状态。Up 表示运行中,Exited 标识已停止
PORTS: 容器内部包括的端口映射到的主机端口
NAMES: 容器的名称

2-3 停止

# 停止容器的运行,容器并未删除。它还可以再次启动、运行。
docker stop <容器名>

2-4 启动

配合" docker stop 命令使用。

容器停止( stop )后,如果需要重新访问该容器中的程序,需要通过 docker start 重新启动该容器。

前提是改容器已存在,且处于 Exited 状态。

如果一个容器曾经并未成功运行( 例如,docker run mysql 忘记了 -e ),那么,即便它存在,你也无法 start 它(因为,逻辑上它无法启动)。

# 启动已停止的容器
docker start <容器名>
# 重启容器
docker restart <容器名>

2-5 删除容器

# 删除已停止的容器
docker rm <容器名>
# 删除正在运行的容器
docker rm -f <容器名>
# 删除所有容器
docker rm -f $(docker ps -aq)

2-6 进入容器

docker exec -it <容器名> /bin/bash

2-7 退出容器

exit 

2-8 查看容器日志

# 查看此前的日志信息(一次性)
docker logs <容器名>
# 持续查看日志信息
docker logs -f <容器名>

3.数据卷相关命令

数据卷( volume )是一个虚拟目录,指向宿主机文件系统中的某个目录。

一旦完成数据卷挂载,对容器的一切操作都会作用在数据卷对应的宿主机目录了。

简单来说,我们将宿主的一个目录和容器中的一个目录映射到了同一个磁盘空间。

这样一来,我们操作宿主机的 /var/lib/docker/volumes/html 目录,就等于操作容器内的 /usr/share/nginx/html 目录了。

作用命令举例
创建一个数据卷docker volume create
显示一个或多个数据卷的信息docker volume inspect
列出所有的数据卷docker volume ls
删除未使用的数据卷docker volume prune
删除一个或多个指定的数据卷docker volume rm

3-1 创建一个数据卷

docker 创建的数据卷都在宿主机的 “/var/lib/docker/volumes/” 目录下。

# 方式一(本质上是方式二的简写)
docker volume create <自定义卷名>

# 方式二
docker volume create --name <自定义卷名>

# 例如
docker volume create mysql-3306-data
# 操作成功时,返回的是刚刚创建的数据卷的卷名

3-2 挂载数据卷

docker run -d --rm --name nginx-80 \
    -v nginx-80-html:/root/html \
    -p 80:80 \
    nginx:stable

步骤1:创建容器并挂载数据卷到容器内的 HTML 目录

docker run --name nginx-80 -v html:/usr/share/nginx/html -p 80:80 -d nginx

步骤2:进入 html 数据卷所在位置,并修改 HTML 内容

# 创建数据卷
docker volume create html

# 查看html数据卷的位置
docker volume inspect html

# 进入该目录
cd /var/lib/docker/volumes/html/_data

# 修改文件
vi index.html

注意

在用 -v 挂载宿主机的目录时,如果宿主机的目录(也就是 -v 的 “:” 前一部分)不存在,那么 docker 会地为你创建这个目录。

但是但是!

目录里的内容是空的!

也就是说,这个空目录的内容覆盖了你挂载容器内的对应目录内容,你容器内的对应目录内容会变成空。

3-3 挂载宿主机文件

从某种思路来说,你可以认为 “挂载数据卷” 和 “挂载宿主机目录” 是批量挂载,而 “挂载宿主机文件” 是单一挂载。

● -v 数据卷名:容器内目录
● -v 宿主机目录:容器内目录
● -v 宿主机文件:容器内文件

四、高级

1.Docker Compose

1-1 安装与卸载

卸载

sudo rm /usr/local/bin/docker-compose
# 验证,查看docker-compose版本
docker-compose -v

安装

  • 第 1 步:确认服务器上是否已安装 docker-compose 命令

    执行如下命令:

    docker-compose -v
    

    如果出现类似如下内容,则证明已安装 docker-compose:

    Docker Compose version v2.2.2
    

    此时,则无须再次安装 docker-compose 。跳过以下内容,直接进入使用环节。

    如果出现类似如下内容,则证明还未安装 docker-compose:

    -bash: docker-compose: command not found
    
  • 第 2 步:下载 docker-compose 二进制程序

    网速和人品都不错的时候,你可以从 docekr-compse 的 github 仓库( 或者国内的 daocloud )下载( 优先考虑从 daocloud 下载,速度更快 ):

    # sudo curl \ 
    #   -L "https://github.com/docker/compose/releases/download/v2.6.0/docker-compose-$(uname -s)-$(uname -m)" \
    #   -o /usr/local/bin/docker-compose
    
    sudo curl \
        -L https://get.daocloud.io/docker/compose/releases/download/v2.6.0/docker-compose-`uname -s`-`uname -m` \
        -o /usr/local/bin/docker-compose
    

    你可以通过修改 URL 中的版本,可以自定义您的需要的版本。

  • 第 3 步:启用 docker-compose 命令

    chmod +x /usr/local/bin/docker-compose
    
    ln -s /usr/local/bin/docker-compose \
        /usr/bin/docker-compose
    
    docker-compose -v
    

1-2 命令

命令选项说明
-f 指定使用的 Compose 模板文件,默认为 docker-compose.yml
-p 指定项目名称, 默认将使用所在目录名称作为项目名
–verbose输出更多调试信息
-v打印版本并退出

1-2-1 重要命令

docker-compose 等同于 docker-compose -f docker-compose.yml 命令,很显然,默认的编排文件的文件名是 docker-compose.yml 。

另外,可以有多个 -f 指定多个配置文件,在项目合作中,可以利用这个特性将一个 docker-compose.yml 配置文件拆成几个,每个项目成员负责一个。

注意:如果你的编排文件的文件名不是 docker-compose.yml,那么你就需要使用 -f 选项给指定。

ps

docker-compose -f xxx.yml ps

# 有资料说是,列出项目中目前的所有容器。
# 但是经测试,-f xxx.yml 没有什么作用,效果是显示由 docker-compose 启动的所有容器,包括 xxx.yml 中所没有的。但是,不会包含由 docker run 直接启动的容器。
# 注意,如果使用 docker ps 命令,那么其结果会同时含有 docker run 和 docker-compose 启动的所有的容器。

up

docker-compose -f xxx.yml up

# 该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。

down

docker-compose -f xxx.yml down

# 此命令停止用 up 命令所启动的容器并移除网络。

restart

docker-compose -f xxx.yml logs

# 重启项目中的服务。用法跟上面的 stop,start 一样。

logs

docker-compose -f xxx.yml ps

# 查看服务容器的输出。默认情况下,docker-compose 将对不同的服务输出使用不同的颜色来区分。可以通过 --no-color 来关闭颜色。该命令在调试问题的时候十分有用。如

docker-compose -f xxx.yml logs # 查看整体的日志

docker-compose -f xxx.yml logs elasticsearch # 查看单独容器的日志

1-2-2 次要命令

如果你的编排文件的文件名不是 docker-compose.yml,那么你就需要使用 -f 选项给指定。

config

docker-compose -f xxx.yml config

# 验证 Compose 文件格式是否正确,若正确则显示配置,若格式错误显示错误原因。
# 此命令不会执行真正的操作,而是显示 docker-compose 程序解析到的配置文件内容。

images

docker-compose -f xxx.yml images

# 列出 Compose 文件中包含的镜像。

stop

docker-compose -f xxx.yml stop

# 停止已经处于运行状态的容器,但不删除它。通过 docker-compose start 可以再次启动这些容器。
# 如果不指定 service 时是默认停止所有的容器。如 docker-compose -f skywalking.yml stop elasticsearch
# 选项:-t, --timeout <TIMEOUT> 停止容器时候的超时(默认为 10 秒)。

start

docker-compose -f xxx.yml start

# 启动已经存在的服务容器。用法跟上面的 stop 刚好相反。如果不指定 service 时是默认启动所有的容器。

build

docker-compose -f xxx.yml build

# 构建(重新构建)项目中的服务容器。
# 一般搭配自定义镜像,比如编写的 Dockfile ,功能类似于 docker build .

1-2-3 关键命令

docker-compose up

docker-compose -f xxx.yml up 命令十分强大,它将尝试自动完成包括构建镜像,( 重新 )创建服务,启动服务,并关联服务相关容器的一系列操作。

  • docker-compose -f xxx.yml up -d

    默认情况,docker-compose up 启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。

    如果使用docker-compose up -d 将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项。

  • docker-compose -f xxx.yml up --no-recreate

    默认情况,如果服务容器已经存在,docker-compose up 将会尝试停止容器,然后重新创建(保持使用 volumes-from 挂载的卷),以保证新启动的服务匹配 docker-compose.yml 文件的最新内容。

    如果用户不希望容器被停止并重新创建,可以使用 docker-compose up --no-recreate 。这样将只会启动处于停止状态的容器,而忽略已经运行的服务。

  • docker-compose -f xxx.yml up --no-deps -d <SERVICE_NAME>

    如果用户只想重新部署某个服务,可以使用 docker-compose up --no-deps -d <SERVICE_NAME> 来重新创建服务并后台停止旧服务,启动新服务,并不会影响到其所依赖的服务。

docker-compose -f xxx.yml up 命令总结

  1. -d 在后台运行服务容器。
  2. –no-color 不使用颜色来区分不同的服务的控制台输出。
  3. –no-deps 不启动服务所链接的容器。
  4. –force-recreate 强制重新创建容器,不能与 --no-recreate 同时使用。
  5. –no-recreate 如果容器已经存在了,则不重新创建,不能与 --force-recreate 同时使用。
  6. –no-build 不自动构建缺失的服务镜像。
  7. -t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。

1-3 docker-compose.yml 文件

默认的模板文件名称为 docker-compose.yml,格式为 YAML 格式。其内容例如:

version: '3'
services:
  mysql-3306:
    container_name: mysql-3306
    image: mysql:8.0
    network_mode: "bridge"
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_ROOT_HOST=%
    volumes:
      - ./3306/conf.d:/etc/mysql/conf.d
      - ./3306/mysql.conf.d:/etc/mysql/mysql.conf.d
      - ./3306/data:/var/lib/mysql
    ports:
      - "3306:3306"

注意每个服务都必须通过 image 指令指定镜像或 build 指令( 需要 Dockerfile )等来自动构建生成镜像。如果使用 build 指令,在 Dockerfile 中设置的选项( 例如:CMD, EXPOSE, VOLUME, ENV 等 )将会自动被获取,无需在 docker-compose.yml 中重复设置。

docker-compose.yml 文件内容详解 :

images

指定为镜像名称或镜像 ID 。如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。

image: apache/skywalking-oap-server:6.5.0
image: apache/skywalking-ui:6.5.0

ports

暴露端口信息。使用 宿主端口:容器端口 (HOST:CONTAINER)格式,或者仅仅指定容器的端口(宿主将会随机选择端口)都可以,端口字符串都使用引号包括起来的字符串格式。

ports: 
    - "3000" # 等价于 "3000:3000"
    - "8080:8080" 
    - "127.0.0.1:8001:8001" # 比较「啰嗦」的写法。少见。

volumes

数据卷所挂载路径设置。可以设置为宿主机路径(HOST:CONTAINER)或者数据卷名称(VOLUME:CONTAINER),并且可以设置访问模式(HOST:CONTAINER:ro)。

volumes:
  - /app/skywalking/elasticsearch/data:/usr/share/elasticsearch/data:rw
  - conf/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml

ulimits

指定容器的 ulimits 限制值。例如,指定最大进程数为 65535 ,指定文件句柄数为 20000(软限制,应用可以随时修改,不能超过硬限制)和 40000(系统硬限制,只能 root 用户提高)。

ulimits:
  nproc: 65535
  nofile:
    soft: 20000
    hard: 40000

depends_on

解决容器的依赖、启动先后的问题。以下例子中会先启动 redis mysql 再启动 web

version: '3'
services:
  web:
    build: .
    depends_on:
      - db
      - redis

  redis:
    image: redis

  db:
    image: mysql

environment

设置环境变量。你可以使用数组或字典两种格式。

environment: # 数组式写法。典型标志是:有 - 号,有 = 号。
  - SW_STORAGE=elasticsearch
  - SW_STORAGE_ES_CLUSTER_NODES=elasticsearch:9200

environment: # 字典式写法。典型标志是:没有 - 号,没有 = 号。有 : 号。
  SW_STORAGE: elasticsearch
  SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200

restart

指定容器退出后的重启策略为始终重启。该命令对保持服务始终运行十分有效,在生产环境中推荐配置为 always 或者 unless-stopped 。

restart: always

1-4 docker-compose 中自动创建数据卷

docker-compose 文件中有一个 volumes 元素,用于指定将要使用的数据卷。例如:

volumes:
  xxx:
  yyy:
  zzz:

本来应该是写成 xxx:{}yyy:{}zzz:{} 的,只不过这里的 {} 被省略掉了。

volumes 元素和 service 元素是平级的兄弟关系

位置的上下关系无所谓,但是不要错搞成了父子关系。

version: '3'
volumes:
    ...
services:
    ...

如果 docker 的对应目录下没有相关的数据卷,docker 会根据 docker-compose 中所写的内容去创建。创建出来的数据卷的名字前面会拼上『项目名』,并以 _ 连接。例如:tmp_xxxtmp_yyytmp_zzz

docker-compose.yml 文件所在的目录,就是项目名。

version: '3'

volumes:
  mysql-3306-data:

# 一定一定注意缩进关系!
services:
  mysql-3306:
    image: mysql:8.0
    network_mode: "bridge" # 默认值。or "host"
    container_name: mysql-3306
    mem_limit: 512m # 限定 docker 容器内存大小
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_ROOT_HOST=% 
    volumes:
      - /etc/localtime:/etc/localtime:ro # 设置时区
      - mysql-3306-data:/var/lib/mysql # 数据目录
    ports:
      - 3306:3306

对于上面使用卷标的写法,你可能需要使用下面的命令查看卷标信息:

# 查看所有卷标
docker volume ls 

# 查看批量的卷标
docker volume ls | grep mysql

# 查看 volume 详情
docker volume inspect docker_mysql-3306-data

和 docker rm 的情况类似,docker-compose down 不会删除数据卷。docker-compose 会删除网络。如果你反而需要在 down 的时候删除,就直接加参数 --volumes

2.Dockerfile

2-1 语法指令

Dockerfile 的语法非常简单,常用的只有 11 个:

命令说明示例
FROM基于哪个镜像来实现FROM centos:7
MAINTAINER镜像的作者MAINTAINER <人名/组织名>
ENV声明环境变量ENV key value
RUN执行命令RUN yum install gcc
COPY添加宿主机文件到容器里COPY ./xxx.tar.gz /tmp
EXPOSE容器内应用可使用端口EXPOSE 8080
CMD容器启动后所执行的程序。 如果执行 docker run 后面跟启动命令会被覆盖掉
ENTRYPOINT与 CMD 功能相同,但是 docker run 不会覆盖。 如果需要覆盖可增加参数 --entrypoint 来覆盖ENTRYPOINT java -jar xx.jar
VOLUME将宿主机容器的目录挂载到容器里

最简单的情况下,我们未来只用到了其中的 FROM、COPY、EXPOSEENTRYPOINT 四个。

FROM 指令

FORM 指令必须是第一条非注释指令。

Docker 的镜像都是分层构建的,一个镜像实际上是多层「累加、叠加」的而成的。最低层被称为 bootfs 。当然,我们不必每次构建镜像都从最底层 bootfs 开始,我们可以直接在某个现成的镜像基础之上开始「叠加」。

FROM 指令就是用来指定我们所要构建的镜像是基于哪个镜像建立的。它有 2 种形式:

FROM <IMAGE>
FROM <IMAGE>:<TAG>

通过 FROM 指定的镜像名称必须是一个已经存在的镜像,这个镜像称之为基础镜像。

以下是 mysql 的 Dockerfile 中的 FROM 片段:

FROM debian:buster-slim

未来,我们构造自己的 spring-boot 项目镜像使用的是 openjdk 镜像

FROM openjdk:8-jre-alpine

COPY 指令

在构建容器的过程中,通常需要将一些( 宿主机中准备好的 )软件源码、配置文件、执行脚本等导入到镜像的构建过程,这时可以使用 COPY 指令将文件从外部传递到镜像内部。

COPY 指令的使用形式:

COPY <src1> <src2> <src3> ... <dest>

虽然,源路径可以有多个,但是通常常见的情况下,COPY 指令也就只有一个源路径、一个目的路径。

COPY 指令的源路径是一个相对路径,相对于 Dockerfile 文件所在的那个位置。

以下是 nginx Dockerfile 中的 COPY 指令片段:

COPY docker-entrypoint.sh /
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
COPY 20-envsubst-on-templates.sh /docker-entrypoint.d
COPY 30-tune-worker-processes.sh /docker-entrypoint.d

EXPOSE 指令

指定运行该镜像的容器使用的端口,可以是多个。

EXPOSE <port> [<port> ...]

使用这个指令的目的是告诉应用程序容器内应用程序会使用的端口,在运行时还需要使用 -p 参数指定映射端口。这是 docker 处于安全的目的,不会自动打开端口。

ENTRYPOINT 指令

ENTRYPOINT 命令指定的是容器运行时的执行程序。

ENTRYPOINT <command> <param1> <param2>

2-2 基于 openjdk 构建 Java 项目(最简版)

第 1 步:准备 jar 包

修改示例项目的 pom.xml 中的 finalName ,以确保项目执行 mvn package 时打成的包叫 app.jar( 以简化后续的操作 )。

<build>  
    <finalName>app</finalName> 
	...
</build>

​ 使用 mvn clean package 打包项目,将 app.jar 包上传到服务器上。

第 2 步:放在一起

新建一个空的目录,然后在目录中新建一个文件,命名为 Dockerfile 。

并将上一步 app.jar 也移入这个文件夹中。

此时,Dockerfile 和 app.jar 是平级关系。

第 3 步:编写 Dockerfile

  1. 基于 openjdk:8-jre-alpine 作为基础镜像
  2. 将 app.jar 拷贝到镜像中
  3. 暴露端口
  4. 编写入口 ENTRYPOINT
FROM openjdk:8-jre-alpine
COPY ./app.jar /tmp/app.jar
EXPOSE 8080
ENTRYPOINT java -jar /tmp/app.jar

第 4 步:使用 docker build 命令构建镜像

docker build -t javaweb:1.0 .

第 5 步: 使用 docker run 创建容器并运行

docker run --rm --name spring-boot-test \
	-p 8080:8080 \
	-e "APP_OPTS=--spring.profiles.active=dev" \
	javaweb:1.0

第 6 步:在 docker-compose 中使用

version: '3'

services:
  spring-boot-demo:
    image: javaweb:1.0
    ports:
      - "8080:8080"

因为前面通过 docker build 使我们的本地镜像仓库中已经有了 spring boot 项目的镜像,我们直接"使用"它即可。

第 7 步:docker-compose 场景下的一个小改进

在之前的场景中,我们在编写了 Dockerfile 之后,使用 docker build 命令手动构建镜像。

docker-compose 命令可"帮"我们 build :新增docker-compose.yml文件

version: '3'

services:
  spring-boot-demo:
    build:
      context: . # Dockerfile 文件所在路径
      dockerfile: Dockerfile # Dockerfile 文件名,可省略
    ports:
      - "8080:8080"

再使用 docker-compose up 命令时,你会看到有构建过程。

docker-compose up --build

因为没有指定镜像名,所以 docker-compose 会以 project-name( 即,文件夹名 )和 service-name 的组合来为镜像命名。

如果你不喜欢默认的镜像名,你就加上 images 指定它。

如果不加 --build ,docker-compose 的会无视 build 这一段配置,像使用普通镜像一样,去本地仓库中查找镜像,如果本地仓库没有,它会去中央仓库下载。

只有加上了 --build 之后,build 这一段配置才会起到应有的效果:根据指定的 Dockerfile 编译镜像。

2-3 基于 openjdk 构建 Java 项目(改进版)

极简版的问题

我们在 spring-boot 项目中可能( 大概率是一定会 )会利用它的多配置文件特性,通过 spring.profiles.active 来控制不同的环境中使用不同的配置信息。

但是极简版的 Dockerfile 在这个功能的支持上面非常不灵活,无法做到"动态"决定哪个 profile 被激活使用。

第 1 步:改进 Dockerfile

FROM openjdk:8-jdk-alpine
ENV APP_OPTS="" //设置环境变量
COPY ./app.jar /tmp/app.jar
EXPOSE 8080
ENTRYPOINT java -jar /tmp/app.jar $APP_OPTS //引用环境变量

上述的改版比原版多利用了一个 Dockerfile 的知识点:设置环境变量,并在镜像的启动命令中使用了这个环境变量。

第 2 步:使用 docker build 命令构建镜像

docker build -t javaweb:1.0 .

第 3 步:使用 docker run 创建容器并运行

这次在运行容器时,指定了为 APP_OPTS "变量"赋值。根据 Dockerfile 的规则,APP_OPTS 变量的值会拼接在 java -jar 命令之后,从而影响到了 spring-boot 项目。

docker run --rm --name spring-boot-test \
	-p 8080:8080 \
	-e "APP_OPTS=--spring.profiles.active=dev" \ //为上面设置的环境变量赋值
	javaweb:1.0

第 4 步:改进 docker-compose.yml

version: '3'

services:
  spring-boot-demo:
    build:
      context: . # Dockerfile 文件所在路径
    environment:
        APP_OPTS: "--spring.profiles.active=prod"
    ports:
      - "8080:8080"

2-4 基于openjre构建的Java微服务项目

第1步: 在每个微服务项目中创建Dockerfile文件

当前文件Dockerfile放置的位置为微服务src同级目录

FROM openjdk:8-jre-alpine
ENV APP_OPTS=""
COPY ./target/app.jar /tmp/app.jar
EXPOSE 8080
ENTRYPOINT java -jar /tmp/app.jar $APP_OPTS

第2步:更改了resource目录下的application文件

server.port=8080
spring.application.name=department-service
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.name=defaultDataSource
spring.datasource.url=jdbc:mysql://department_service_db/department_service_db?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.cloud.nacos.discovery.server-addr=nacos-server:8848

其中department_service_db为第4步中自定义的数据库服务名,nacos-server为第4步中自定义的nacos的服务名

其他微服务也同样操作

第3步:使用mvn clean package命令打包微服务

需要在src同级下进行打包

mvn clean package

第4步:在微服务的父项目下编写docker-compose.yaml文件

version: "3"
  
    volumes:
      department-service-db-data: {}
      employee-service-db-data: {} 
      
    nacos-server:
      container_name: nacos-server
      image: nacos/nacos-server:2.0.3
      environment:
        - MODE=standalone
      volumes:
        - /etc/localtime:/etc/localtime:ro
      ports:
        - 8848:8848

    # 微服务1
    department-service:
      build:
       context: ./department-service
      image: department-service:1.1.1.0


    # 微服务2
    employee-service:
       build:
         context: ./employee-service
       image: employee-service:1.1.1.0


    # 微服务1数据库
    department_service_db:
      container_name: department-service-db-hl
      image: mysql:8.0
      environment:
        - MYSQL_ROOT_PASSWORD=123456
      volumes:
        - department-service-db-data:/var/lib/mysql

    # 微服务2数据库
    employee_service_db:
      container_name: employee-service-db-hl
      image: mysql:8.0
      environment:
        - MYSQL_ROOT_PASSWORD=123456
      volumes:
        - employee-service-db-data:/var/lib/mysql

    # 网关
    gateway-service:
      build: ./gateway
      image: gateway-service:1.1.1.0
      ports:
        - 8080:8080

第5步:使用docker-compose命令进行启动

docker-compose -f docker-compose.yaml up -d --build 
-f 为指定文件(如果文件名为docker-compsoer则可以省略)
up 为构建镜像并启动
-d 为项目后台启动
--build 如果项目第一次启动请进行编译

第6步:通过命令查看项目启动的情况

docker-compose ps -a查看所有通过docker-compose运行的服务

[root@localhost docker-spring-cloud-parent]# docker-compose ps -a
NAME                                              COMMAND                  SERVICE                 STATUS              PORTS
department-database                               "docker-entrypoint.s…"   department-database     running             33060/tcp
department-service-db-hl                          "docker-entrypoint.s…"   department_service_db   running             33060/tcp
docker-spring-cloud-parent-department-service-1   "/bin/sh -c 'java -j…"   department-service      running             8080/tcp
docker-spring-cloud-parent-employee-service-1     "/bin/sh -c 'java -j…"   employee-service        running             9090/tcp
docker-spring-cloud-parent-gateway-1              "/bin/sh -c 'java -j…"   gateway                 running             0.0.0.0:6666->6666/tcp, :::6666->6666/tcp

STATUS=exited为服务已停止。

STATUS=running为服务运行中。

docker-composer logs <服务名 > 查看该服务的日志

docker-compose logs department-service

一般是数据库或者nacos服务连接失败

如果是数据库问题,检查application文件或者数据库库名

如果是nacos服务连接失败,一般是nacos服务启动较慢,微服务启动在前导致的不能连接到nacos,这时重启下微服务即可。

注意事项之-不注意就会出现奇奇怪怪的bug

注意1:docker-compose.yaml文件一定注意要缩进对齐

如果遇到报错类似:

yaml: line 31: did not find expected key

检查发现内容并无错误,极有可能是提示的行与上面行未对齐。即使是不同的service,同一个docker-compose.yaml文件中层级之间也必须对齐。

注意2:gateway网关的端口号不能为6666

如果一切配置ok,顺利启动,所有服务都没有任何报错,查看nacos服务列表,一切服务正常…但试图访问项目,前台页面提示 ERR_UNSAFE_PORT。

无法访问此网站网址为 http://192.172.0.210:6666/department-service/department/1 的网页可能暂时无法连接,或者它已永久性地移动到了新网址。
ERR_UNSAFE_PORT

虽然不知道为什么。但原因可能是你的网关端口号设置成了6666,尽管它并没有被占用,你的后台服务也并没有任何的报错,但就是提示无法访问网站。

此时随便改个端口号,如7777,再试,可能就ok了。

神奇的bug。

(注意修改端口号要修改Java项目配置文件application.properties端口号;修改该项目对应的Dockerfile文件端口号,修改整个父项目docker-compose.yaml文件中gateway网关端口号,三者要保持同步,改完重新打包项目。)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K13NSa26-1661947017522)(C:\Users\z\AppData\Roaming\Typora\typora-user-images\image-20220831193911718.png)]

相关文章:

  • HTML5 day_01(8.5)
  • 跑路了,去东北国企干软件测试一个月的感触
  • datawhale8月组队学习《pandas数据处理与分析》(中)(变形、连接、缺失数据)
  • recording:34. 在排序数组中查找元素的第一个和最后一个位置
  • 【论文阅读】Globally Consistent and Tightly Coupled 3D LiDAR Inertial Mapping
  • Java8 特性(二):Optional 相关操作
  • y119.第七章 服务网格与治理-Istio从入门到精通 -- Istio流量治理快速入门(五)
  • 以字符串的形式返回文件名扩展名
  • 机械硬盘数据拷贝
  • 计算机毕业设计java毕设项目之ssm中医药配方小程序
  • 【C++】内存管理 + 初识模板
  • 猿创征文|我的技术成长之路,一名Python学者在CSDN的蜕变
  • java基于ssm的高校人事员工工资管理系统
  • QML初学者教程
  • 速卖通详情接口接口调用示例
  • CEF与代理
  • IDEA常用插件整理
  • java第三方包学习之lombok
  • Java面向对象及其三大特征
  • js写一个简单的选项卡
  • Vultr 教程目录
  • Windows Containers 大冒险: 容器网络
  • 高度不固定时垂直居中
  • 规范化安全开发 KOA 手脚架
  • 微信小程序:实现悬浮返回和分享按钮
  • 用Visual Studio开发以太坊智能合约
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • # Panda3d 碰撞检测系统介绍
  • #DBA杂记1
  • #预处理和函数的对比以及条件编译
  • $L^p$ 调和函数恒为零
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (2)STL算法之元素计数
  • (动态规划)5. 最长回文子串 java解决
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (转)大道至简,职场上做人做事做管理
  • (转)为C# Windows服务添加安装程序
  • (转载)hibernate缓存
  • (转载)虚函数剖析
  • .libPaths()设置包加载目录
  • .NET : 在VS2008中计算代码度量值
  • .NET HttpWebRequest、WebClient、HttpClient
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .net6使用Sejil可视化日志
  • .net操作Excel出错解决
  • .net和php怎么连接,php和apache之间如何连接
  • .net解析传过来的xml_DOM4J解析XML文件
  • .NET开发不可不知、不可不用的辅助类(一)
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • @TableId注解详细介绍 mybaits 实体类主键注解
  • [1525]字符统计2 (哈希)SDUT
  • [AIGC 大数据基础]hive浅谈