docker笔记

一、docker简介

1.什么是docker

Docker 是一个开源的应用容器引擎,由于docker影响巨大,今天也用"Docker" 指代容器化技术。

2.docker的优势
一键部署,开箱即用
容器使用基于image镜像的部署模式,image中包含了运行应用程序所需的一切:代码、运行时、系统工具、系统库和配置文件。
无论是单个程序还是多个程序组成的复杂服务,或者分布式系统,都可以使用 docker run 或 docker compose up命令一键部署,省去了大量搭建、配置环境、调试和排查错误的时间。
一次打包,到处运行
Docker 为容器创建了行业标准,使容器成为了软件交付过程中的一种标准化格式,将软打包成容器镜(image),能够使软件在不同环境下运行一致,应用程序可以快速可靠地从一个环境移植到另外一个环境,并确保在所有的部署目标(例如开发、测试、生产环境)上都按预期运行,从而避免了“在我电脑上是好的,怎么到你那却不能用了?”的问题。

3.容器与虚拟机

容器包括应用程序及其所有依赖项。容器运行时,与宿主机共享操作系统内核,容器在linux内核层面(使用 Cgroupsnamespaces)来实现进程间的隔离,容器在主机操作系统上的用户空间中作为独立进程运行。
因此,容器相比于虚拟机更加轻量化,它体积小,启动快,占用资源少,性能好。
虚拟机使用虚拟化技术,应用程序运行在完整的操作系统(OS)之上,因此占用的资源更多,安装更复杂。
但是由于容器与宿主机共享内核,所以在隔离性和安全性方面不如虚拟机。

二、安装docker

1.Windows下安装Docker

 
注意事项:
容器主要使用linux内核技术,因此Windows下安装docker可能会有遇到各种问题,建议刚入门的同学先在linux虚拟机里安装docker,学完之后在windows下安装,免得遇到问题后,还没入门就放弃了。

 

 

 

2.linux下安装Docker


安装环境:CentOS 7.3+
如果之前安装了旧版docker,请先删除。
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
sudo yum install -y yum-utils

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
安装docker engine
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
启动docker,运行hello world查看是否成功
 
sudo systemctl start docker
sudo docker run hello-world
配置国内镜像仓库地址:
新建/etc/docker/daemon.json文件,输入如下内容:
{
  "registry-mirrors": [
    "https://registry.docker-cn.com",
    "http://hub-mirror.c.163.com",
    "https://fsp2sfpr.mirror.aliyuncs.com/"
  ]
}
然后重启,配置开机启动
sudo systemctl restart docker
sudo systemctl enable docker
sudo systemctl enable containerd

三、docker run 开箱即用

1.docker架构

 
registry 镜像仓库
registry可以理解为镜像仓库,用于保存docker image。
Docker Hub 是docker官方的镜像仓库,docker命令默认从docker hub中拉取镜像。我们也可以搭建自己的镜像仓库。

image 镜像
image可以理解为一个只读的应用模板。image包含了应用程序及其所需要的依赖环境,例如可执行文件、环境变量、初始化脚本、启动命令等。

container 容器
容器是image的一个运行实例。当我们运行一个image,就创建了一个容器。


2.docker pull 拉取镜像

从镜像仓库拉取镜像到本地
docker pull nginx 不写默认是latest
docker pull nginx:latest
docker pull nginx:1.22
docker pull nginx:1.22.0-alpine
一般不建议使用latest,因为最新的镜像是滚动更新的,过一段时间,可能跟你本地的不是同一个。
使用docker images命令查看本地镜像

3.docker run 命令

docker run [可选参数] 镜像名:版本 []

公开端口:-p 宿主机ip:容器ip
docker run --name some-nginx -d -p 8080:80 nginx:1.22
默认情况下,容器无法通过外部网络访问。需要使用-p参数将容器的端口映射到宿主机端口,才可以通过宿主机IP进行访问。浏览器打开 http://192.168.56.106:8080
-p 8080-8090:8080-8090 公开端口范围,前后必须对应
-p 192.168.56.106:8080:80 如果宿主机有多个ip,可以指定绑定到哪个ip
 
后台运行docker run --name db-mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
使用run命令,部署mysql,docker先去本地查找镜像,如果找不到,就去docker hub中拉取镜像
  ●--name 定义容器的名称
  ●-e 声明环境变量
  ●-d容器在后台运行
  ●查看容器ip
docker inspect \
	--format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' db-mysql
docker start db-mysql 启动容器
docker stop 关闭容器
docker restart 重启容器
docker rm 删除容器
前台交互运行

创建一个新的容器,使用mysql客户端
docker run -it --rm mysql:5.7 mysql -h172.17.0.2 -uroot -p

-it 使用交互模式,可以在控制台里输入、输出
--rm在容器退出时自动删除容器。一般在使用客户端程序时使用此参数。
如果每次使用客户端都创建一个新的容器,这样将占用大量的系统空间。其中mysql -h172.17.0.2 -uroot -p 表示启动容器时执行的命令。

docker exec在运行的容器中执行命令,一般配合-it参数使用交互模式,docker exec -it db-mysql /bin/bash

常用命令:
docker ps 查看正在运行的容器
docker ps -a 查看所有容器,包括正在运行和停止的
docker inspect 查看容器的信息
docker logs查看日志
docker cp 在容器和宿主机间复制文件
docker cp ./some_file 容器名:/work
docker cp 容器名:/var/logs/ /tmp/app_logs

四、docker 网络

 

默认网络

docker会自动创建三个网络,bridge,host,none


bridge桥接网络


如果不指定,新创建的容器默认将连接到bridge网络。
默认情况下,使用bridge网络,宿主机可以ping通容器ip,容器中也能ping通宿主机。
容器之间只能通过 IP 地址相互访问,由于容器的ip会随着启动顺序发生变化,因此不推荐使用ip访问。


host


慎用,可能会有安全问题。
容器与宿主机共享网络,不需要映射端口即可通过宿主机IP访问。(-p选项会被忽略)
主机模式网络可用于优化性能,在容器需要处理大量端口的情况下,它不需要网络地址转换 (NAT),并且不会为每个端口创建“用户空间代理”。


none


禁用容器中所用网络,在启动容器时使用。

用户自定义网络

创建用户自定义网络
docker network create my-net
将已有容器连接到此网络
docker network connect my-net db-mysql
创建容器时指定网络。
docker run -it --rm --network my-net mysql:5.7 mysql -hdb-mysql -uroot -p
在用户自定义网络上,容器之间可以通过容器名进行访问。
用户自定义网络使用 Docker 的嵌入式 DNS 服务器将容器名解析成 IP。

主机名解析

hostname
容器的hostname默认为容器的 ID。

docker run -it -d --hostname my-alpine --name my-alpine alpine:3.15

docker inspect \
	--format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-alpine

 /etc/hosts

在容器内手动修改/etc/hosts文件,容器重启后会恢复默认配置。
要是/etc/hosts修改生效,使用--add-host
docker run --add-host=my-alpine:172.17.0.3 -it --rm alpine:3.15

 五、docker存储

将数据存储在容器中,一旦容器被删除,数据也会被删除。同时也会使容器变得越来越大,不方便恢复和迁移。
将数据存储到容器之外,这样删除容器也不会丢失数据。一旦容器故障,我们可以重新创建一个容器,将数据挂载到容器里,就可以快速的恢复。

 存储方式

docker 提供了以下存储选项
 

volume 卷

卷存储在主机文件系统分配一块专有存储区域,由 Docker(在 Linux 上)管理,并且与主机的核心功能隔离。非 Docker 进程不能修改文件系统的这一部分。卷是在 Docker 中持久保存数据的最佳方式

bind mount 绑定挂载

绑定挂载可以将主机文件系统上目录或文件装载到容器中,但是主机上的非 Docker 进程可以修改它们,同时在容器中也可以更改主机文件系统,包括创建、修改或删除文件或目录,使用不当,可能会带来安全隐患

tmpfs 临时挂载

tmpfs挂载仅存储在主机系统的内存中,从不写入主机系统的文件系统。当容器停止时,数据将被删除。

绑定挂载(bind mount)

绑定挂载适用以下场景:
  ●将配置文件从主机共享到容器。
  ●在 Docker 主机上的开发环境和容器之间共享源代码或编译目录。
    ○例如,可以将 Maven 的target/目录挂载到容器中,每次在主机上用 Maven打包项目时,容器内都可以使用新编译的程序包。
-v
绑定挂载将主机上的目录或者文件装载到容器中。绑定挂载会覆盖容器中的目录或文件。如果宿主机目录不存在,docker会自动创建这个目录。但是docker只自动创建文件夹,不会创建文件。
例如,mysql的配置文件和数据存储目录使用主机的目录。可以将配置文件设置为只读(read-only)防止容器更改主机中的文件。
docker run -e MYSQL_ROOT_PASSWORD=123456 \
           -v /home/mysql/mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro  \
           -v /home/mysql/data:/var/lib/mysql  \
           -d mysql:5.7 

tmpfs 临时挂载

临时挂载将数据保留在主机内存中,当容器停止时,文件将被删除。

volume卷

卷 是docker 容器存储数据的首选方式,卷有以下优势:
  ●卷可以在多个正在运行的容器之间共享数据。仅当显式删除卷时,才会删除卷。
  ●当你想要将容器数据存储在外部网络存储上或云提供商上,而不是本地时。
  ●卷更容易备份或迁移,当您需要备份、还原数据或将数据从一个 Docker 主机迁移到另一个 Docker 主机时,卷是更好的选择。
创建和挂载卷:
docker volume create my-data

docker run -e MYSQL_ROOT_PASSWORD=123456 \
           -v /home/mysql/conf.d/my.cnf:/etc/mysql/conf.d/my.cnf:ro  \
           -v my-data:/var/lib/mysql  \
           -d mysql:5.7 
创建nfs卷
docker volume create --driver local \
    --opt type=nfs \
    --opt o=addr=192.168.1.1,rw \
    --opt device=:/path/to/dir \
    vol-nfs

六、部署自己的应用

本例子我们使用docker来部署一个应用系统,RuoYi是一款用java编写的,基于SpringBoot+Bootstrap的后台管理系统。
ruoyi官方文档:http://doc.ruoyi.vip/ruoyi/
源码下载:https://gitee.com/y_project/RuoYi/tree/v4.7.4/

配置文件中修改了端口、数据库连接信息。
#application.yml文件
server:
  # 服务器的HTTP端口,默认为80
  port: 8080
  
  
  
#application-druid.yml文件
  url: jdbc:mysql://ruoyi-db:3306/ry?useUnicode=true&characterEncoding=utf8
  username: root
  password: 123456

将源码编译打包成ruoyi-admin.jar文件,放到宿主机/home/app目录下,/home/app/sql目录下放的是数据库初始化脚本。

准备工作:
创建网络和存储卷
docker volume create ruoyi-data
docker network create ruoyi-net
部署mysql并初始化数据库,我们在创建数据库容器的时候,需要做三件事:
  ●创建数据库ry
  ●设置字符集为utf-8
  ●执行数据库初始化脚本
使用MYSQL_DATABASE环境变量创建数据库,设置字符集--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci,容器使用/docker-entrypoint-initdb.d目录下的脚本初始化数据库,脚本可以是.sh .sql.sql.gz这三种格式。
docker run -e MYSQL_ROOT_PASSWORD=123456 \
           -e MYSQL_DATABASE=ry \
           -v /home/app/sql:/docker-entrypoint-initdb.d \
           -v ruoyi-data:/var/lib/mysql  \
           --network ruoyi-net \
           --name ruoyi-db \
           -d mysql:5.7 \
           --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
部署应用
docker run -p 8080:8080 \
                    -v /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar \
                    --network ruoyi-net \
                    --name ruoyi-java \
                    -d openjdk:8u342-jre \
                    java -jar /usr/local/src/ruoyi-admin.jar
如果端口被some-nginx 占用,停掉nginx:docker stop some-nginx

如果容器名字重复,删掉该容器:docker rm ruoyi-java

解决乱码问题:

乱码问题是容器中mysql默认字符集引起的,我们需要将默认字符集改为utf8mb4。参考:https://github.com/docker-library/mysql/issues/131
可以进入容器,使用以下命令查看数据库字符集:
docker exec -it ruoyi-db mysql -uroot -p
>show variables like '%character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.03 sec)
 
注意:由于删除容器不会删除存储卷,修改字符集需要删除存储卷,不然已经导入的数据字符集不会发生改变
删除容器和卷
docker stop ruoyi-db
docker rm ruoyi-db
docker volume rm ruoyi-data
可以通过以下两种解决方法:
1.修改运行参数
使用环境变量LANG=C.UTF-8设置客户端字符集
docker run  -e MYSQL_ROOT_PASSWORD=123456 \
            -e MYSQL_DATABASE=ry \
            -e LANG=C.UTF-8 \
            -v /home/app/sql:/docker-entrypoint-initdb.d \
            -v ruoyi-data:/var/lib/mysql  \
            --network ruoyi-net \
            --name ruoyi-db \
            -d mysql:5.7 \
            --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
或者
使用--skip-character-set-client-handshake忽略客户端字符集,使用客户端和服务端字符集一致 
docker run  -e MYSQL_ROOT_PASSWORD=123456 \
            -e MYSQL_DATABASE=ry \
            -v /home/app/sql:/docker-entrypoint-initdb.d \
            -v ruoyi-data:/var/lib/mysql  \
            --network ruoyi-net \
            --name ruoyi-db \
            -d mysql:5.7 \
            --skip-character-set-client-handshake --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci 
2.修改配置文件
修改/home/mysql/mysql.cnf
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
init-connect='SET NAMES utf8mb4'

[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4
将配置文件挂载到容器中
docker run -e MYSQL_ROOT_PASSWORD=123456 \
           -e MYSQL_DATABASE=ry \
           -v /home/mysql/mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro  \
           -v /home/app/sql:/docker-entrypoint-initdb.d \
           -v ruoyi-data:/var/lib/mysql  \
           --network ruoyi-net \
           --name ruoyi-db \
           -d mysql:5.7

七、docker compose容器编排

在实际工作中,部署一个应用可能需要部署多个容器,一个一个部署非常不方便。docker compose可以一键部署和启动多个容器,它使用yaml文件来编排服务。
github和docker hub很多项目都提供了docker-compose.yaml文件,我们可以一键部署项目,非常方便。

一键部署wordpress

wordpress是一个著名的开源博客系统。
将以下内容保存到本地的docker-compose.yml文件中。
docker compose命令启动时,默认在当前目录下寻找compose.yamlcompose.yml,为了兼容之前的版本,也会查找docker-compose.yamldocker-compose.yml
也可以使用-f参数手动指定文件docker compose -f docker-compose-dev.yml up -d
version: '3.1'

services:

  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wordpress:/var/www/html

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql

volumes:
  wordpress:
  db:
docker compose up -d一键部署启动
docker compose start/stop启动/停止服务
docker compose down停止并删除容器,不会删除存储卷volume
老版本docker用docker-compose    区别
删除卷:
docker column ls
docker volumn rm ...多个卷名
 
进入容器,可以使用:
docker exec -it wordpress_wordpress_1 /bin/bash
docker compose exec -it wordpress /bin/bash
可以使用docker compose -p my up -d定义自己的容器前缀为my,容器名为my_wordpress_1

compose文件结构

docker-compose.yml通常需要包含以下几个顶级元素:

version 已弃用,早期版本需要此元素。
services必要元素,定义一个或多个容器的运行参数
在services中可以通过以下元素定义容器的运行参数
  image 容器 镜像
  ports端口映射
  environment环境变量
  networks容器使用的网络
  volumes容器挂载的存储卷
  command容器启动时执行的命令
  depends_on定义启动顺序
复数形式(例如ports,networks,volumes,depends_on)参数需要传入列表
  networks创建自定义网络
  volumes 创建存储卷
yaml文件语法
缩进代表上下级关系
  缩进时不允许使用Tab键,只允许使用空格
  :键值对,后面必须有空格
  -列表,后面必须有空格
  [ ]数组
  #注释
  {key:value,k1:v1}map
  | 多行文本块
如果一个文件中包含多个文档
  ---表示一个文档的开始

例子:

还有一种常见的用法:
把公共的配置提取出来,用&来建立锚点,<<合并到当前数据,用*引用锚点,例如
version: '3.7'

# Settings and configurations that are common for all containers
x-minio-common: &minio-common
  image: quay.io/minio/minio:RELEASE.2022-08-13T21-54-44Z
  command: server --console-address ":9001" http://minio{1...2}/data{1...2}
  expose:
    - "9000"
    - "9001"
  
services:
  minio1:
  #公共配置合并到当前应用
    <<: *minio-common
    volumes:
      - data1-1:/data1
      - data1-2:/data2

  minio2:
    <<: *minio-common
    volumes:
      - data2-1:/data1
      - data2-2:/data2

volumes:
  data1-1:
  data1-2:
  data2-1:
  data2-2:

编排自己的项目

以ruoyi项目为例子,先采用挂载目录的方式部署应用,等我们学完dockfile打包,就可以完整的部署应用了。
version: '3.1'

services:    

  ruoyi-app:
    #  docker run --name ruoyi-app      \
    #             -p 8080:8080        \
    #             --network ruoyi-net      \
    #             -v /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar   \
    #             -d openjdk:8u342-jre    \
    #             java -jar /usr/local/src/ruoyi-admin.jar
    image: openjdk:8u342-jre
    ports:
      - 8080:8080
    volumes:
      - /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar
    command: java -jar /usr/local/src/ruoyi-admin.jar
    networks:
      - ruoyi-net
      #ruoyi-db数据库先启动,再启动ruoyi-net
    depends_on:
      - ruoyi-db
  
  ruoyi-db:
    #  docker run --name ruoyi-db -p 3303:3306 \
    #             --network ruoyi-net        \
    #             -v ruoyi-data:/var/lib/mysql  \
    #             -v /home/app/sql:/docker-entrypoint-initdb.d   \
    #             -e MYSQL_DATABASE=ry         \
    #             -e MYSQL_ROOT_PASSWORD=123456    \
    #             -d mysql:5.7      \
    #             --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --skip-character-set-client-handshake
    image: mysql:5.7
    environment: 
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_DATABASE=ry
    command: [
      "--character-set-server=utf8mb4",
      "--collation-server=utf8mb4_general_ci",
      "--skip-character-set-client-handshake"
      ]
    volumes:
      - /home/app/sql:/docker-entrypoint-initdb.d
      - ruoyi-data:/var/lib/mysql
    networks:
      - ruoyi-net
      
volumes:
  ruoyi-data:

networks:
  ruoyi-net:
command支持以下写法:
#推荐使用数组或列表的方式
#数组
command:
	["java",
  "-jar",
  "/usr/local/src/ruoyi-admin.jar"
	]
#列表
command: 
	- java
  - -jar
  - /usr/local/src/ruoyi-admin.jar

# shell命令模式
command: java -jar /usr/local/src/ruoyi-admin.jar
执行复杂的脚本
command:
  - bash
  - "-c"
  - |
    set -ex
    # Generate mysql server-id from pod ordinal index.
    [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
    ordinal=${BASH_REMATCH[1]}
    echo [mysqld] > /mnt/conf.d/server-id.cnf
    # Add an offset to avoid reserved server-id=0 value.
    echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
    # Copy appropriate conf.d files from config-map to emptyDir.
    if [[ $ordinal -eq 0 ]]; then
      cp /mnt/config-map/primary.cnf /mnt/conf.d/
    else
      cp /mnt/config-map/replica.cnf /mnt/conf.d/
    fi       
environment支持如下两种写法:
# 使用map
environment:
    MYSQL_DATABASE: exampledb
    MYSQL_USER: exampleuser
    MYSQL_PASSWORD: examplepass
    MYSQL_RANDOM_ROOT_PASSWORD: '1'

#使用列表
environment:
    - MYSQL_ROOT_PASSWORD=123456
    - MYSQL_DATABASE=ry
    - LANG=C.UTF-8

容器启动顺序depends_on

数据库初始化完成之前,不会建立connections。

depends_on只能保证容器的启动和销毁顺序,不能确保依赖的容器是否ready
version: "3.9"
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres
在这个例子中,depends_on只能保证web容器在db,redis之后启动,不会关注他们的状态是否启动完成或准备就绪。
要确保应用服务在数据库初始化完成后再启动,需要配合conditionhealthcheck使用。
services:
  web:
    build: .
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
  redis:
    image: redis
  db:
    image: postgres
condition有三种状态:
  service_started容器已启动
  service_healthy容器处于健康状态
  service_completed_successfully容器执行完成且成功退出(退出状态码为0)
我们来改造一下我们自己的docker-compose.yaml文件,完整例子如下:
services: 

  ruoyi-app:
    #  docker run --name ruoyi-app      \
    #             -p 8080:8080        \
    #             --network ruoyi-net      \
    #             -v /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar   \
    #             -d openjdk:8u342-jre    \
    #             java -jar /usr/local/src/ruoyi-admin.jar
    image: openjdk:8u342-jre
    restart: always
    ports:
      - 8080:8080
    networks:
      - ruoyi-net
    volumes:
      - /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar
    command: [ "java", "-jar", "/usr/local/src/ruoyi-admin.jar" ]
    #若容器成功启动,但容器的状态不等于容器内应用的状态。需要对容器进行健康检查,确保容器内应用健康运行
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 20s
    depends_on:
      ruoyi-db:
        condition: service_healthy

  ruoyi-db:
    #  docker run --name ruoyi-db -p 3303:3306 \
    #             --network ruoyi-net        \
    #             -v ruoyi-data:/var/lib/mysql  \
    #             -v /home/app/sql:/docker-entrypoint-initdb.d   \
    #             -e MYSQL_DATABASE=ry         \
    #             -e MYSQL_ROOT_PASSWORD=123456    \
    #             -d mysql:5.7      \
    #             --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --skip-character-set-client-handshake
    image: mysql:5.7
    environment:
      - MYSQL_DATABASE=ry
      - MYSQL_ROOT_PASSWORD=123456
    volumes:
      - ruoyi-data:/var/lib/mysql
      - /home/app/sql:/docker-entrypoint-initdb.d
    networks:
      - ruoyi-net
    command:
      [
        "--character-set-server=utf8mb4",
        "--collation-server=utf8mb4_unicode_ci",
        "--skip-character-set-client-handshake"
      ]
    healthcheck:
      test: ["CMD", 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD']
      interval: 15s
      timeout: 5s
      retries: 5
      start_period: 20s

volumes:
  ruoyi-data:

networks:
  ruoyi-net:

八、dockerfile制作镜像

dockerfile
dockerfile通常包含以下几个常用命令:
FROM ubuntu:18.04
WORKDIR /app
COPY . .
RUN make .
CMD python app.py
EXPOSE 80
FROM 打包使用的基础镜像
WORKDIR相当于cd命令,进入工作目录
COPY 将宿主机的文件复制到容器内
RUN打包时执行的命令,相当于打包过程中在容器中执行shell脚本,通常用来安装应用程序所需要的依赖、设置权限、初始化配置文件等
CMD运行镜像时执行的命令
EXPOSE指定容器在运行时监听的网络端口,它并不会公开端口,仅起到声明的作用,公开端口需要容器运行时使用-p参数指定。

制作自己的镜像

参考我们之前的配置,进入/home/app目录下,制作dockerfile文件
  ruoyi-java:
    image: openjdk:8u342-jre
    ports:
      - 8080:8080
    volumes:
      - /home/app/ruoyi-admin.jar:/usr/local/src/ruoyi-admin.jar
    command: [ "java", "-jar", "/usr/local/src/ruoyi-admin.jar" ]
    networks:
      - ruoyi-net
    depends_on:
      - ruoyi-db
编写dockerfile文件
FROM openjdk:8u342-jre
WORKDIR /app
COPY ./ruoyi-admin.jar .
CMD [ "java", "-jar", "ruoyi-admin.jar" ]
EXPOSE 8080
docker build . 打包
docker images 查看镜像id
 

docker tag 6299285c3336 ruoyi-app:4.7.4-jar 设置镜像的标签

 
可以修改docker-compose.yaml文件,使用已经打包的镜像。
 
应用程序打包在镜像中,不需要使用volumes,command已经在dockerfile中。

image镜像与layer层

image文件由一系列层构建而成,dockerfile每一个命令都会生成一个层。每一层都是只读的。例如前面我们制作镜像,就产生了4个层。


也可以使用    docker image history 容器id    命令查看

 
创建容器时,会创建一个新的可写层,通常称为“容器层”。对正在运行的容器所做的所有更改(如写入新文件、修改现有文件和删除文件)都将写入容器层,而不会修改镜像。
 

 

多阶段构建

在构建基于 Java 的应用程序时,需要一个 JDK 将源代码编译为 Java 字节码。但是,在生产中不需要该 JDK。
多阶段构建可以将生成时依赖与运行时依赖分开,减小整个image文件大小。
 

Maven/Tomcat 示例

使用 Maven来构建应用,在最终的image中不需要包含maven。我们可以使用多阶段构建,每一个阶段从FROM开始,最终的image只会从最后一个阶段构建,不会包含前面阶段产生的层,因此可以减少镜像体积。
在项目目录下新建dockerfile文件:
FROM maven AS build
WORKDIR /source
COPY . .
RUN mvn package

FROM  openjdk:8u342-jre
WORKDIR /app
COPY --from=build /source/ruoyi-admin/target/ruoyi-admin.jar .
EXPOSE 80
ENTRYPOINT ["java","-jar","ruoyi-admin.jar"]
注:
RUN是编译时执行的命令,CMD是编译完成运行时候执行的命令
AS起别名。--from=build 从build所在阶段去 拷贝。
docker build -t ruoyi-jar:latest .      -t相当于docker tag
 
 
java -jar ruoyi-admin.jar --spring.datasource.druid.master.url:xxx可以覆盖配置文件中的url参数。
可以在docker-compose.yaml中command中写上参数,覆盖配置文件中的参数。command 中的参数会传递给dockerfile中的ENTRYPOINT里。
version: '3.1'

services:
  ruoyi-java:
    image: ruoyi-jar:4.7.4
    command: [
      "--ruoyi.profile=/home/ruoyi/uploadPath",
      "--spring.datasource.druid.master.url=jdbc:mysql://ruoyi-db:3306/ry?useUnicode=true&characterEncoding=utf8",
      "--spring.datasource.druid.master.username=root",
      "--spring.datasource.druid.master.password=123456"
      ]
    ports:
      - 8080:8080
    networks:
      - ruoyi-net
    depends_on:
      - ruoyi-db

  ruoyi-db:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_DATABASE=ry
    command: [
      "--character-set-server=utf8mb4",
      "--collation-server=utf8mb4_general_ci",
      "--skip-character-set-client-handshake"
      ]
    volumes:
      - /home/app/sql:/docker-entrypoint-initdb.d
      - ruoyi-data:/var/lib/mysql
    networks:
      - ruoyi-net


volumes:
  ruoyi-data:

networks:
  ruoyi-net:

ENTRYPOINT和CMD的区别

dockerfile应该至少包含一个ENTRYPOINTCMD
ENTRYPOINT指定容器启动时执行的默认程序,一般运行容器时不会被替换或覆盖。
除非使用--entrypoint进行指定。
docker run -it --entrypoint /bin/bash redis 
CMD可以在启动容器时被替换和覆盖。
例如docker run -it --rm mysql:5.7 /bin/bash
如果镜像中ENTRYPOINTCMD都存在,则CMD将作为ENTRYPOINT的参数使用。
 
参考:

posted on 2022-11-24 16:49  passionConstant  阅读(97)  评论(0编辑  收藏  举报