Go语言 如何在Docker编写中运行一次命令

laximzn5  于 2022-12-28  发布在  Go
关注(0)|答案(4)|浏览(143)

我正在编写一个Docker compose文件来部署我的Go Web服务器,我的服务器使用mongo,所以我在docker compose中添加了一个数据卷容器和mongo服务,然后我编写了一个Dockerfile来构建我的Go项目,最后运行它。
但是,还有一个步骤必须要做,一旦我的项目已经编译好了,我必须运行下面的命令:第一个月
这将添加一些必要的信息到数据库中,并且这些信息只需要添加一次。但是我不能在Dockerfile中添加这一步(在构建过程中),因为mongo必须已经启动。
那么,我如何才能做到这一点呢?即使我重新启动服务器,然后再次运行docker-compose up,我也不希望这个命令再次执行。
我想我错过了一些Docker的理解,因为我实际上并不了解关于数据卷容器的一切(它们只是挂载卷的 stopped 容器吗?)。另外,如果我重新启动服务器,然后运行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

下面是我的Docker文件,用于构建我的项目映像:

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
lnlaulya

lnlaulya1#

我建议在容器中添加一个入口点脚本;在这个入口点脚本中,您可以检查数据库是否已经初始化,如果没有,则执行所需的步骤。
正如您在问题中所注意到的,服务/容器的启动顺序不应被视为理所当然,因此有可能您的应用程序容器在数据库容器之前启动,因此脚本应考虑到这一点。
As an example, have a look at the official WordPress image, which performs a one-time initialization of the database in it's entrypoint-script. The script attempts to connect to the database (and retries if the database cannot be contacted (yet)), and checks if initialization is needed; 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>,则删除该卷

uajslkp6

uajslkp62#

您可以尝试使用ONBUILD指令:
ONBUILD指令将向映像添加一个触发器指令,该触发器指令将在以后映像用作另一个生成的基础时执行。该触发器将在下游生成的上下文中执行,就像它已在下游Dockerfile中紧接着FROM指令插入一样。
任何构建指令都可以注册为触发器。
如果您要构建的映像将用作构建其他映像的基础,例如应用程序构建环境或可以使用用户特定配置自定义的守护进程,则此功能非常有用。
例如,如果您的映像是一个可重用的Python应用程序构建器,则需要将应用程序源代码添加到特定目录中,并且可能需要在此之后调用构建脚本。您现在不能调用ADDRUN,因为您还没有访问应用程序源代码的权限。您可以简单地为应用程序开发人员提供一个样板文件Dockerfile,以便复制粘贴到他们的应用程序中,但这样做效率低下、容易出错并且难以更新,因为它与特定于应用程序的代码混合在一起。
解决方案是使用ONBUILD注册高级指令,以便在下一个构建阶段运行。
下面是它的工作原理:
1.当遇到ONBUILD指令时,构建器会向正在构建的映像的元数据添加一个触发器。该指令不会影响当前构建。
1.在构建结束时,所有触发器的列表存储在映像清单中的键OnBuild下,可以使用docker inspect命令检查它们。
1.稍后,可以使用FROM指令将该映像用作新构建的基础。作为处理FROM指令的一部分,下游构建器查找ONBUILD触发器,并按照注册它们的顺序执行它们。如果任何触发器失败,FROM指令被中止,这又导致构建失败。如果所有触发成功,则FROM指令完成,并且构建照常继续。
1.触发器在执行后会从最终映像中清除。换句话说,它们不会被"孙子"构建继承。

qq24tv8q

qq24tv8q3#

您的应用程序需要一些初始状态才能工作。这意味着您应该:
1.检查所需状态是否已存在
1.取决于第一步结果初始化状态
您可以编写程序来检查当前数据库状态(这里我将使用bash脚本,但它可以是任何其他语言程序):

RUN if $(./check.sh); then my_project -setup; fi

在我的例子中,如果脚本将返回0(成功退出状态),则将调用setup命令。

lymnna71

lymnna714#

在docker-compose中,您可以定义:
重新启动:否
只运行容器一次,这对于数据库迁移容器很有用。

相关问题