如何在Docker中运行一次命令撰写

时间:2016-04-04 15:59:53

标签: mongodb go docker

所以我正在使用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

3 个答案:

答案 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:

  1. When it encounters an ONBUILD instruction, the builder adds a trigger to the metadata of the image being built. The instruction does not otherwise affect the current build.
  2. At the end of the build, a list of all triggers is stored in the image manifest, under the key OnBuild. They can be inspected with the docker inspect command.
  3. Later the image may be used as a base for a new build, using the 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.
  4. Triggers are cleared from the final image after being executed. In other words they are not inherited by “grand-children” builds.

答案 2 :(得分:-1)

Your application need some initial state for working. It means that you should:

  1. Check if required state already exists
  2. Depends on first step result init state or not

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.