所以我正在使用docker compose文件来部署我的Go web服务器。我的服务器使用mongo,所以我在docker compose中添加了一个数据卷容器和mongo服务。 然后我写了一个Dockerfile来构建我的Go项目,最后运行它。
然而,还有另一个步骤必须完成。编译完项目后,我必须运行以下命令:
./my-project -setup
这会向数据库添加一些必要的信息,而信息只需添加一次。 但是我无法在Dockerfile上添加此步骤(在构建过程中),因为mongo必须已经启动。
那么,我怎样才能做到这一点?即使我重新启动服务器然后再次运行docker-compose up
我也不希望再次执行此命令。
我认为我错过了一些Docker的理解,因为我实际上并不了解数据量容器的所有内容(他们只是已停止装载卷的容器?)。
此外,如果我重新启动服务器,然后运行docker-compose up
,将运行哪些命令?它是否会启动与现在使用给定CMD停止的相同容器?
无论如何,这是我的docker-compose.yml:
version: '2'
services:
mongodata:
image: mongo:latest
volumes:
- /data/db
command: --break-mongo
mongo:
image: mongo:latest
volumes_from:
- mongodata
ports:
- "28001:27017"
command: --smallfiles --rest --auth
my_project:
build: .
ports:
- "6060:8080"
depends_on:
- mongo
- mongodata
links:
- mongo
这是我的Dockerfile来构建我的项目图像:
FROM golang
ADD . /go/src/my_project
RUN cd /go/src/my_project && go get
RUN go install my_project
RUN my_project -setup
ENTRYPOINT /go/bin/my_project
EXPOSE 8080
答案 0 :(得分:7)
我建议在你的容器中添加一个入口点脚本;在此入口点脚本中,您可以检查数据库是否已初始化,如果不是,请执行所需的步骤。
正如您在问题中所注意到的那样,服务/容器的启动顺序不应该被视为理所当然,因此您的应用程序容器可能在数据库容器之前启动,因此脚本应该考虑到这一点。
作为一个例子,看一下官方的WordPress图像,它在它的入口点脚本中执行数据库的一次性初始化。该脚本尝试连接到数据库(如果无法联系数据库,则重试),并检查是否需要初始化; https://github.com/docker-library/wordpress/blob/df190dc9c5752fd09317d836bd2bdcd09ee379a5/apache/docker-entrypoint.sh#L146-L171
注意强>
我注意到您创建了一个“仅数据容器”来附加您的卷。自docker 1.9以来,docker具有卷管理功能,包括命名卷。因此,您不再需要使用“仅数据”容器。
您可以从撰写文件中删除仅限数据的容器,并将您的mongo服务更改为如下所示;
mongo:
image: mongo:latest
volumes:
- mongodata:/data/db
ports:
- "28001:27017"
command: --smallfiles --rest --auth
这应该创建一个名为mongodata
的新卷(如果它不存在),或者重新使用具有该名称的现有卷。您可以使用docker volume ls
列出所有卷,如果不再需要,则删除包含docker volume rm <some-volume>
的卷
答案 1 :(得分:3)
You could try to use ONBUILD
instruction:
The ONBUILD
instruction adds to the image a trigger instruction to be executed at a later time, when the image is used as the base for another build. The trigger will be executed in the context of the downstream build, as if it had been inserted immediately after the FROM
instruction in the downstream Dockerfile
.
Any build instruction can be registered as a trigger.
This is useful if you are building an image which will be used as a base to build other images, for example an application build environment or a daemon which may be customized with user-specific configuration.
For example, if your image is a reusable Python application builder, it will require application source code to be added in a particular directory, and it might require a build script to be called after that. You can’t just call ADD
and RUN
now, because you don’t yet have access to the application source code, and it will be different for each application build. You could simply provide application developers with a boilerplate Dockerfile
to copy-paste into their application, but that is inefficient, error-prone and difficult to update because it mixes with application-specific code.
The solution is to use ONBUILD
to register advance instructions to run later, during the next build stage.
Here’s how it works:
ONBUILD
instruction, the builder adds a trigger to the metadata of the image being built. The instruction does not otherwise affect the current build.OnBuild
. They can be inspected with the docker inspect
command.FROM
instruction. As part of processing the FROM
instruction, the downstream builder looks for ONBUILD
triggers, and executes them in the same order they were registered. If any of the triggers fail, the FROM
instruction is aborted which in turn causes the build to fail. If all triggers succeed, the FROM
instruction completes and the build continues as usual.答案 2 :(得分:-1)
Your application need some initial state for working. It means that you should:
You can write program for checking current database state (here I will use bash script but it can be every other language program):
RUN if $(./check.sh); then my_project -setup; fi
In my case if script will return 0 (success exit status) then setup
command will be called.