Docker
Docker 是什么?
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app), 更重要的是容器性能开销极低。
为什么使用 Docker?
这里我们先思考一下传统的项目部署有什么痛点?
- 项目更新发布及部署低效,过程繁琐且需要人工介入,每次加机器都需要再重新搭环境
- 环境一致性难以保证,多个服务器环境有可能还有差异
- 不同环境之间迁移成本太高,例如:Windows 迁移到 Linux 又需要重新再搭建环境
- 使用虚拟机部署的话又太笨重,资源消耗大,不够轻量
再看看使用 docker 的优势
-
轻量级:Docker 容器只包含应用程序及其依赖项,相对于传统的虚拟机来说更加轻量级,可以更快地启动和停止。
-
可移植性:Docker 容器可以在不同的环境中运行,包括开发、测试和生产环境,而不需要担心环境差异导致的问题。
-
一致性:Docker 容器可以确保应用程序及其依赖项在不同的环境中运行时具有相同的行为,这可以避免由于环境差异导致的问题。
-
隔离性:Docker 容器可以隔离应用程序及其依赖项,避免它们之间的冲突,这可以提高应用程序的稳定性和安全性。
-
可扩展性:Docker 容器可以很容易地扩展,可以根据需要启动多个容器来处理更多的请求。
-
开放性:Docker 容器是开放的,可以在不同的平台上运行,这可以提高应用程序的可移植性和互操作性。
所以有了 Docker 可以很大程度解决上面的问题。
Docker 的三个概念
-
镜像(Image):类似于虚拟机中的镜像,是一个包含有文件系统的面向 Docker 引擎的只读模板。任何应用程序运行都需要环境,而镜像就是用来提供这种运行环境的。例如一个 Ubuntu 镜像就是一个包含 Ubuntu 操作系统环境的模板。
-
容器(Container):类似于一个轻量级的沙盒,可以将其看作一个极简的 Linux 系统环境。Docker 引擎利用容器来运行、隔离各个应用。容器是镜像创建的应用实例,可以创建、启动、停止、删除容器,各个容器之间是是相互隔离的,互不影响。注意:镜像本身是只读的,容器从镜像启动时,Docker 在镜像的上层创建一个可写层,镜像本身不变。
-
仓库(Repository):类似于代码仓库,这里是镜像仓库,是 Docker 用来集中存放镜像文件的地方。一般每个仓库存放一类镜像,每个镜像利用 tag 进行区分,比如 Ubuntu 仓库存放有多个版本(20.04、22.04 等)的 Ubuntu 镜像。
docker 常用命令
docker build
使用 Dockerfile 创建镜像
常用参数如下:
-t # 为镜像指定一个名称和标签
-f # 指定Dockerfile的路径和文件名
--no-cache # 不使用缓存构建镜像
--build-arg # 设置构建时的参数
--squash # 将多个镜像层压缩成一个层,减小镜像大小
-m # 设置内存最大值
--rm # 构建镜像成功后删除中间容器
```shell
[root@VM-16-4-centos search-blog-api]# docker build --rm -t search-blog-api:latest .
docker run
创建并启动一个新的容器
常用参数如下:
-d # 以后台模式运行容器
-it # 以交互模式运行容器
--name # 为容器指定一个名称
-p # 将容器内部的端口映射到宿主机的端口
-v # 将宿主机的目录或文件挂载到容器内部
--rm # 容器停止后自动删除
-e # 设置环境变量
--network # 指定容器所在的网络
--link # 将容器连接到另一个容器
```shell
[root@VM-16-4-centos search-blog-api]# docker run -d --restart always --name redis6 -p 6378:6379 -v /data/docker/redis6/data:/data redis:6.2.12 --requirepass 123456 --appendonly yes
6153bf26bb092dd74464ec697fe6df4e8b74a9e386b9ea3907ced8fd3e7c7b8b
[root@VM-16-4-centos search-blog-api]# docker run -d --restart=always -p 8000:80 -p 4433:443 --name nginx2 -v /data/docker/nginx2/nginx.conf:/etc/nginx/nginx.conf -v /data/docker/nginx2/conf.d/:/etc/nginx/conf.d nginx
e1046a12a7584e2bd03816633f9446a24f31fd90d8b120fbc286200db7162312
docker start/stop/restart/kill
启动 / 停止 / 重启 / 杀掉容器
[root@VM-16-4-centos search-blog-api]# docker start search-blog-api
search-blog-api
[root@VM-16-4-centos search-blog-api]# docker stop search-blog-api
search-blog-api
[root@VM-16-4-centos search-blog-api]# docker restart search-blog-api
search-blog-api
[root@VM-16-4-centos search-blog-api]# docker kill search-blog-api
search-blog-api
docker rm
删除容器,删除前必须先停止容器,可以一次性删除多个容器
[root@VM-16-4-centos search-blog-api]# docker stop nginx2 redis6
nginx2
redis6
[root@VM-16-4-centos search-blog-api]# docker rm nginx2 redis6
nginx2
redis6
docker exec
在运行的容器中执行命令
常用参数如下:
-i # 以交互模式运行容器。
-t # 为容器分配一个伪终端。
-d # 在后台模式下运行容器。
--user # 指定要执行命令的用户
```shell
[root@VM-16-4-centos search-blog-api]# docker exec -it search-blog-api /bin/sh -c "pwd && echo 'hello world'"
/var/www/search-blog-api
hello world
[root@VM-16-4-centos search-blog-api]# docker exec -it search-blog-api /bin/sh
/var/www/search-blog-api # pwd && echo 'hello world'
/var/www/search-blog-api
hello world
[root@VM-16-4-centos search-blog-api]# docker exec -it --user root search-blog-api /bin/sh
/var/www/search-blog-api # whoami
root
docker ps
列出容器(正在运行)
常用参数如下:
-a # 列出所有容器,包括已停止的容器。
-q # 仅列出容器的 ID。
--filter # 根据指定的条件过滤容器。
--format # 指定输出格式。
```shell
[root@VM-16-4-centos search-blog-api]# docker ps -aq --no-trunc --format "{{.ID}} {{.Names}}"
2e99f53709204152466112e9d39289ae683fb51fae6579a2abc93f57fab920ae search-blog-api
0059d4f74e1fc7accf695e2686b812c9537a592b3decacd45cf4380de2c09279 chatgpt-next-web
75c26e4930f0b40c87f889d9bf26b9379ff191c3b02355f759926b67872256ff clash
2305014aa58247ff1e7f1d5cc6bc00a88a06fa80d998c485eed16f0cb0bc108b proxy-provider-converter
52cee28fb9f2ce5eb58480e8c71db670874ce062e6c6c48d518e082c8280a09b nginx
96accd461318a6f454fb2dc68ba0d028148f3042831738bfbedc632282fd1fa9 blog-springboot
docker logs
获取容器的日志
常用参数如下:
-f # 跟踪日志输出
-t # 显示时间戳
--tail # 只显示最新n条容器日志
--since # 显示某个开始时间的所有日志
```shell
[root@VM-16-4-centos search-blog-api]# docker logs -f search-blog-api
Puma starting in single mode...
* Version 3.12.6 (ruby 2.6.3-p62), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: production
* Listening on tcp://0.0.0.0:8989
Use Ctrl-C to stop
docker cp
用于容器与物理主机之间拷贝文件
[root@VM-16-4-centos ~]# docker cp nginx:/etc/nginx/nginx.conf ./nginx.conf
[root@VM-16-4-centos ~]# ls nginx.conf
nginx.conf
docker images
显示系统本地容器镜像文件
常用参数如下:
-a # 列出所有的镜像(含中间映像层,默认,过滤掉中间映像层);
--digests # 显示镜像的摘要信息;
-f # 显示满足条件的镜像;
--format # 指定返回值的模板文件;
--no-trunc # 显示完整的镜像信息;
-q # 只显示镜像ID。
```shell
[root@VM-16-4-centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
search-blog-api latest fbb48dd23433 53 minutes ago 413MB
chatgpt-next-web 496 26df00c7c340 20 hours ago 244MB
chatgpt-next-web 493 57d3f1ac8673 2 days ago 244MB
node 18-alpine 9752a2a43933 6 days ago 175MB
redis 6.2.12 f2ed029e761a 2 weeks ago 113MB
dreamacro/clash-premium latest 914123588f21 5 weeks ago 32.7MB
ruby 2.6.3-alpine3.10 6ddb199f039f 3 years ago 51MB
docker rmi
删除镜像,可以一次性删除多个镜像
常用参数如下:
-f # 强制删除
```shell
[root@VM-16-4-centos ~]# docker rmi 4ce0e1527dc3 d357a69437f1 d357a69437f1
Deleted: sha256:4ce0e1527dc3deb927be29bc6467f262adc83a0b4786d7de5c41110fa7bc25f1
Deleted: sha256:847c1ad24118136696d4e9db3868c2edb8da31345ff6794a4c915411b8fb03f4
Deleted: sha256:eb0cee5fde822881866744ea907e1276695b956035ef343f67434549d056fe3d
Deleted: sha256:4e4feadd3db131a8a9d653d20d6cc6bd09455ee28d7469af4f14ba26fbdedb01
Deleted: sha256:875489dabca74ace35aaa4663e73b979400e9ddfcd36562606d19a80fac10bda
Deleted: sha256:f426caf54025e79fe35aac1ad2709ae2eaf23205ad4ef915916e9b965ad2839c
Deleted: sha256:5933523e0b7b2dc48e349bcfd411afded1782cb0d252fd7a05c8916186ac7538
Deleted: sha256:5fc1822846db2626e9ee686e7402bf889b972788f10457345b382efb72c43e22
Deleted: sha256:5eedf316a57768adc360fa32bf0d7f6f3d4184f6cd5c6af900128526a7d31cb2
Deleted: sha256:8e31a1f0276ef64656af038aa1f3c8adbe3b4315aa678c39fc0d6a80b4c49fc4
Deleted: sha256:a27895de8166be7c43f67b50163bfe0a92b9b9ece9e1ac42431d63a2eba37f6a
Deleted: sha256:d357a69437f1fff92f544dfec8ad0a088cfc40455b971533b214b90fe665359b
Deleted: sha256:2a58602bc572d084be3e9200ddd27deffbb94e4bf284e39d439b6b60aa244e1f
Deleted: sha256:2f3dd2d9ca0a7b6106ba281aedc109dbe3d401e36bec21602d3a1d16e33481cd
Deleted: sha256:5927c45e49500cbc58e900c620337a15960e8a2f471a322fd8b4e5f8328c034b
Deleted: sha256:63663f6d26cc538eb61cf48a250a98eaebc9f74bca0563daf23e66b47e929942
什么是 Dockerfile?
Dockerfile 是用来构建 Docker 镜像的构建文件,是由一系列命令和参数构成的脚本。构建、运行一个 container 容器的过程可以粗略的分为三步:
- 编写 Dockerfile 文件
- 使用 docker build 命令以 Dockerfile 为基础构建 image 镜像
- 使用 docker run 命令以 image 镜像为基础生成 container 容器
如图:
下面是一个 Rails 项目的 Dockerfile 文件,可以看看都做了什么
# 使用安装了最少的软件的镜像,也有使用 ruby:alpine
FROM ruby:2.6.3-alpine3.10
# 安装依赖
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk update && apk add --no-cache vim tzdata mariadb-connector-c-dev
RUN apk add --no-cache --virtual .temp-build-libs \
build-base gcc musl-dev
# 设置环境变量
ENV RAILS_ROOT /var/www/search-blog-api
ENV RAILS_ENV production
ENV HOST 0.0.0.0
ENV PORT 8989
ENV PIDFILE $RAILS_ROOT/tmp/pids/server.pid
# 设置容器里的工作目录
WORKDIR $RAILS_ROOT
# 创建 rails 程序目录和程序运行所需要的 pids 的目录
RUN mkdir -p $RAILS_ROOT/tmp/pids
# 将 Dockerfile 目录下所有内容复制到容器工作目录
# 包括 Gemfile 及 Gemfile.lock,当 Gemfile 没有改变时,省略下面的 bundle install
COPY . .
RUN pwd && ls -all
# 安装 Rails 环境
RUN bundle install
# 可执行权限
RUN chmod +x $RAILS_ROOT/docker-entrypoint.sh
# 删除不需要的编译依赖
RUN apk del .temp-build-libs
# 暴露服务端口
EXPOSE 8989
# 运行 docker-entrypoint.sh
ENTRYPOINT ["./docker-entrypoint.sh"]
Dockerfile RUN,CMD,ENTRYPOINT 命令区别
- RUN 命令执行命令并创建新的镜像层,通常用于安装软件包,
- CMD 命令设置容器启动后默认执行的命令及其参数,但 CMD 设置的命令能够被 docker run 命令后面的命令行参数替换
- ENTRYPOINT 配置容器启动时的执行命令(不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令)
CMD
CMD 指令允许用户指定容器的默认执行的命令。此命令会在容器启动且 docker run 没有指定其他命令时运行。下面是一个例子:
# Dockerfile
FROM ruby:2.6.3-alpine3.10
RUN echo "RUN hello world"
CMD echo "CMD hello world"
```shell
# 先build镜像,此时RUN命令会被执行:
[root@VM-16-4-centos search-blog-api]# docker build -f Dockerfile.cmd -t demo-cmd:lastest .
Sending build context to Docker daemon 269.8kB
Step 1/3 : FROM ruby:2.6.3-alpine3.10
---> 6ddb199f039f
Step 2/3 : RUN echo "RUN hello world"
---> Running in 6e797bb88ed1
RUN hello world
Removing intermediate container 6e797bb88ed1
---> 4ea84493be2d
Step 3/3 : CMD echo "CMD hello world"
---> Running in 27cc9c449cba
Removing intermediate container 27cc9c449cba
---> e44ba4e0de81
Successfully built e44ba4e0de81
Successfully tagged demo-cmd:lastest
# 运行容器 docker run -it [image] 将输出:
[root@VM-16-4-centos search-blog-api]# docker run -it demo-cmd:lastest
CMD hello world
# 但当后面加上一个命令,比如 docker run -it [image] echo 'hello world' ,CMD 会被忽略掉,命令 echo 'hello world' 将被执行:
[root@VM-16-4-centos search-blog-api]# docker run -it demo-cmd:lastest echo 'hello world'
hello world
ENTRYPOINT
ENTRYPOINT 用于设置容器启动时要执行的命令及其参数,同时可通过 CMD 命令或者命令行参数提供额外的参数。ENTRYPOINT 中的参数始终会被使用,这是与 CMD 命令不同的一点。下面是一个例子:
# Dockerfile
FROM ruby:2.6.3-alpine3.10
RUN echo "hello world"
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
```shell
# 先build镜像,此时RUN命令会被执行:
[root@VM-16-4-centos search-blog-api]# docker build -f Dockerfile.ent -t demo-ent:latest .
Sending build context to Docker daemon 269.8kB
Step 1/4 : FROM ruby:2.6.3-alpine3.10
---> 6ddb199f039f
Step 2/4 : RUN echo "hello world"
---> Running in 52a61e601c05
hello world
Removing intermediate container 52a61e601c05
---> 950e6b92abda
Step 3/4 : ENTRYPOINT ["/bin/echo", "hello"]
---> Running in 676cd9ee4f0a
Removing intermediate container 676cd9ee4f0a
---> 31b83657f33f
Step 4/4 : CMD ["world"]
---> Running in 100b533e37db
Removing intermediate container 100b533e37db
---> 5f3dac6c020d
Successfully built 5f3dac6c020d
Successfully tagged demo-ent:latest
# 当容器通过 docker run -it [image] 启动时,输出为:
[root@VM-16-4-centos search-blog-api]# docker run -it demo-ent:latest
hello world
# 而如果通过 docker run -it [image] RCC 启动,则输出为:
[root@VM-16-4-centos search-blog-api]# docker run -it demo-ent:latest RCC
hello RCC
docker 网络模式
当安装 Docker 时,它会自动创建三个网络。我们可以使用以下 docker network ls
命令列出这些网络:
[root@VM-16-4-centos search-blog-api]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0a183d7a6cda bridge bridge local
79394185106a host host local
0398973f575d none null local
Docker 内置这三个网络,运行容器时,我们可以使用该–network 标志来指定容器应连接到哪些网络。
Docker 有以下 4 种网络模式:
| 网络模式 | 简介 |
| :——– | —————————————————————– |
| bridge | 为每一个容器分配、设置 IP 等,并将容器连接到一个 docker0
虚拟网桥,默认为该模式。 |
| host | 容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。 |
| none | 容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,IP 等。 |
| container | 新创建的容器不会创建自己的网卡和配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。 |
docker 优化镜像体积的技巧
-
使用多阶段构建:使用多个 FROM 指令来构建镜像,每个阶段都可以使用不同的基础镜像和构建步骤。这样可以减少镜像的大小,因为最终镜像只包含必要的文件和依赖项。例子:https://gitlab.explorexd.com/devs/chatgpt-next-web/-/blob/main/Dockerfile
-
删除不必要的文件:在构建镜像时,删除不必要的文件和目录,例如缓存文件、日志文件和临时文件等。
-
使用 Alpine 镜像:Alpine 是一个轻量级的 Linux 发行版,它的镜像非常小,通常只有几十 MB。使用 Alpine 镜像可以减少镜像的大小。
-
合并多个 RUN 指令:在 Dockerfile 中,每个 RUN 指令都会创建一个新的镜像层。因此,将多个 RUN 指令合并成一个可以减少镜像的大小。
-
使用 .dockerignore 文件:在构建镜像时,使用 .dockerignore 文件来排除不必要的文件和目录,这样可以减少构建上下文的大小。
Docker-Compose
Docker-Compose 是什么?
要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等,这些需要多个容器相互配合来完成。
Docker Compose 允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
为什么使用 docker-compose?
使用 Docker Compose 有以下几个好处:
-
简化应用程序的部署:使用 Docker Compose,我们可以轻松地定义和运行多个容器,而不必手动启动和配置每个容器。
-
管理多个容器:Docker Compose 可以管理多个容器,并且可以在单个命令中启动、停止和重建整个应用程序。
-
容器之间的链接和共享数据卷:Docker Compose 支持容器之间的链接和共享数据卷,使得容器之间的通信和数据共享变得更加容易。
-
简化开发环境:使用 Docker Compose,我们可以轻松地在本地创建一个与生产环境相同的开发环境,从而简化了开发和测试过程。
详解 docker-compose.yml
version: '3.9'
services:
search-blog-api:
container_name: search-blog-api # 容器名称
image: search-blog-api:latest # 镜像名称
build: # 指定构建 Docker 镜像的配置
context: ./ # 指定构建上下文的路径
dockerfile: Dockerfile # 指定 Dockerfile 的路径
networks: # 设置服务之间的网络连接
- nginx
restart: always # 定义服务的重启策略,no:不重启服务。always:服务总是重启;on-failure:只有在服务退出代码非零时才重启服务;unless-stopped:除非手动停止服务,否则服务总是重启。
expose: # expose 只是将容器内部的端口暴露出来,而不会将它们映射到主机上。这意味着其他容器可以通过容器名称和端口号访问该容器的服务,但是外部主机无法直接访问该服务
- 8989
environment: # 用于设置容器的环境变量
TZ: 'Asia/Shanghai'
volumes: # 将主机上的目录或文件挂载到容器中
- '/data/docker/search-blog-api/log:/var/www/search-blog-api/log'
mysql:
image: mysql:latest
container_name: mysql
networks:
- nginx
ports: # 将容器内部的端口映射到主机上的端口,以便外部可以访问容器中运行的应用程序
- '3306:3306'
restart: always
env_file: # 从文件中读取环境变量并将其传递给容器
- .env.mysql.db
redis:
image: redis:latest
container_name: redis
networks:
- nginx
ports:
- '6379:6379'
restart: always
networks: # 定义一个名为 nginx 的网络,并指定了其驱动为 bridge 。
nginx:
name: nginx
driver: bridge
docker-compose 常用命令
docker-compose up
启动所有或者某个容器
常用参数如下:
-d # 在后台运行容器。
--build # 构建镜像并启动容器。
--force-recreate # 强制重新创建容器。
--no-recreate # 不重新创建已经存在的容器。
--no-build # 不构建镜像,直接启动容器。
--abort-on-container-exit # 当容器退出时,停止所有容器。
--remove-orphans # 删除孤立的容器。
--scale # 指定服务的容器数量。
```shell
[root@VM-16-4-centos search-blog-api]# docker-compose up --build -d
[root@VM-16-4-centos search-blog-api]# docker-compose up redis
docker-compose down
停止并删除所有或者某个容器
常用参数如下:
-v # 删除容器相关的所有卷。
--rmi # 删除所有相关的镜像。
--remove-orphans # 删除孤立的容器。
--timeout # 指定停止容器的超时时间。
```shell
[root@VM-16-4-centos search-blog-api]# docker-compose down --rmi all
Stopping search-blog-api ... done
Stopping mysql ... done
Stopping redis ... done
Removing search-blog-api ... done
Removing mysql ... done
Removing redis ... done
docker-compose ps
列出所有容器的状态
常用参数如下:
-q # 只显示容器 ID。
--services # 只显示服务名称。
--filter # 根据条件过滤显示的容器。
```shell
[root@VM-16-4-centos search-blog-api]# docker-compose ps --services
search-blog-api
mysql
redis
docker-compose logs
查看所有容器或者某个容器的日志
常用参数如下:
-f # 实时跟踪日志输出。
--tail # 仅显示最后指定数量的日志行。
--timestamps # 显示日志输出的时间戳。
--no-color # 禁用日志输出的颜色。
```shell
[root@VM-16-4-centos search-blog-api]# docker-compose logs -f search-blog-api
Attaching to search-blog-api
search-blog-api | Puma starting in single mode...
search-blog-api | * Version 3.12.6 (ruby 2.6.3-p62), codename: Llamas in Pajamas
search-blog-api | * Min threads: 5, max threads: 5
search-blog-api | * Environment: production
search-blog-api | * Listening on tcp://0.0.0.0:8989
search-blog-api | Use Ctrl-C to stop
docker-compose build
构建所有容器的镜像
--no-cache # 禁用缓存,强制重新构建镜像。
--pull # 在构建镜像之前,先拉取最新的基础镜像。
--parallel # 并行构建多个服务镜像。
```shell
[root@VM-16-4-centos search-blog-api]# docker-compose build
mysql uses an image, skipping
redis uses an image, skipping
Building search-blog-api
Sending build context to Docker daemon 286.7kB
Step 1/18 : FROM ruby:2.6.3-alpine3.10
---> 6ddb199f039f
Step 2/18 : RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
---> Using cache
---> 7a2ce267c778
Step 3/18 : RUN apk update && apk add --no-cache vim tzdata mariadb-connector-c-dev
---> Using cache
---> a4a59cceffcd
Step 4/18 : RUN apk add --no-cache --virtual .temp-build-libs build-base gcc musl-dev
---> Using cache
---> e8f19a4d741a
Step 5/18 : ENV RAILS_ROOT /var/www/search-blog-api
---> Using cache
---> 3b64cdef2323
Step 6/18 : ENV RAILS_ENV production
---> Using cache
---> 284c1d71c30c
Step 7/18 : ENV HOST 0.0.0.0
---> Using cache
---> fe4e69d8969a
Step 8/18 : ENV PORT 8989
---> Using cache
---> 7f0f0e955d07
Step 9/18 : ENV PIDFILE $RAILS_ROOT/tmp/pids/server.pid
---> Using cache
---> af5835d359f0
Step 10/18 : WORKDIR $RAILS_ROOT
---> Using cache
---> e3c69a6905cd
Step 11/18 : RUN mkdir -p $RAILS_ROOT/tmp/pids
---> Using cache
---> 26b4fff07caa
Step 12/18 : COPY . .
---> Using cache
---> 88a83516af1b
Step 13/18 : RUN pwd && ls -all
---> Using cache
---> 9c82786f9417
Step 14/18 : RUN bundle install
---> Using cache
---> 98ba1ed02626
Step 15/18 : RUN chmod +x $RAILS_ROOT/docker-entrypoint.sh
---> Using cache
---> 147463a21366
Step 16/18 : RUN apk del .temp-build-libs
---> Using cache
---> 61b82717b5c3
Step 17/18 : EXPOSE 8989
---> Using cache
---> 4db764d0f6ba
Step 18/18 : ENTRYPOINT ["./docker-entrypoint.sh"]
---> Using cache
---> 12c9d131856f
Successfully built 12c9d131856f
Successfully tagged search-blog-api:latest
分享一下自己积累的 docker-compose 配置
https://github.com/jiaxudonggit/my-docker-compose
评论区