GAE Flexible 上具有不同 dockerfile 的多个服务

Multiple services with different dockerfiles on GAE Flexible

我正在使用 Google AppEngine Flexible with python environment. Right now I have two services: default and worker that share the same codebase, configured by app.yaml and worker.yaml. Now I need to install native C++ library, so I had to switch to Custom runtime 并添加了 Dockerfile。

这里是gcloud beta app gen-config --custom命令生成的Dockerfile

FROM gcr.io/google-appengine/python
LABEL python_version=python3.6

RUN virtualenv --no-download /env -p python3.6

# Set virtualenv environment variables. This is equivalent to running
# source /env/bin/activate
ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH
ADD requirements.txt /app/
RUN pip install -r requirements.txt
ADD . /app/
CMD exec gunicorn --workers=3 --threads=3 --bind=:$PORT aces.wsgi

以前我的 app.yamlworker.yaml 都有自己的 entrypoint: 配置,指定了 运行 启动服务所需的命令。

所以,我的问题是如何使用两个不同的命令来启动服务?

编辑 1

到目前为止,我能够通过为每项服务的每次部署重写 dockerfile 中的 CMD 行来解决这个问题。但是,我对这个解决方案不是很满意。

gcloud app deploy 命令有 --image-url 标志,允许从 GCR 设置图像 url。我还没有对此进行研究,但似乎我可以将图像上传到 GCR 并使用 urls 因为不要经常更改

由于无法更改 Dockerfile 名称,因此不必修改 Dockerfile 的唯一方法是将每个服务存储在其自己的单独目录中。干净分离,每个服务都有自己的 Dockerfile and/or 启动配置。

但这又提出了一个问题:如何处理多个服务共享的代码?使用符号链接(非常适合在标准环境服务之间共享代码)不适用于灵活的环境服务,请参阅 Sharing code between flexible environment modules in a GAE project

我看到了一些可能的方法,none 非常理想,但可能比您目前拥有的更有吸引力:

  • hard-link 每个共享源代码文件(因为硬链接目录是不可能的)。有点乏味且 error-prone,但每个文件只需执行一次
  • 将您的共享代码打包并发布为外部库,添加到使用它的每个服务的 requirements.txt 文件中
  • 将共享代码拆分到一个单独的存储库中,并在每个使用它的服务中都有该存储库的副本(如果使用 git,可能作为一个 git 子模块?)。您只需要确保在服务部署时以正确的版本拉取共享存储库 - 可以通过自动化非常可靠地完成。如果您在此回购协议中有未提交的更改,则会更复杂一些 - 您必须在所有服务中修补相同的更改。
  • 拥有多个名称不同的 Dockerfile 副本,您只需复制这些文件即可,而不必总是编辑同一个文件。符号链接而不是复制 可能 也可以工作,因为符号链接不需要在服务目录之外进行跟踪,如果它只是作为符号链接复制它就可以工作。

所以我的 Java 应用程序也遇到了非常相似的问题。我们希望从 Heroku 迁移到 GAE,并试图用 GAE 服务模拟 Heroku Procfile。实际上,我们所做的是在我们的应用程序 src/main/appengine/websrc/main/appengine/worker 中创建单独的目录,其中每个目录都包含特定于进程的 app.yaml 和 Dockerfile。然后使用 mvn appengine:deploy 功能,我们分别为要部署的每个服务指定 -Dapp.stage.dockerDirectory-Dapp.stage.appEngineDirecory。然后仅使用一些参数,我们基本上就可以从相同的代码库中编写出每个服务的并行部署脚本。不确定这是否适用于您的情况,但它对我们非常有用:以下是完整的两个示例命令:

网络进程: mvn appengine:deploy -Dapp.stage.dockerDirectory=src/main/appengine/web -Dapp.stage.appEngineDirectory=src/main/appengine/web -Dapp.stage.stagingDirectory=target/appengine-web -Dapp.deploy.projectId=${project-id} -Dapp.deploy.version=${project-version}

工作进程: mvn appengine:deploy -Dapp.stage.dockerDirectory=src/main/appengine/worker -Dapp.stage.appEngineDirectory=src/main/appengine/worker -Dapp.stage.stagingDirectory=target/appengine-worker -Dapp.deploy.projectId=${project-id} -Dapp.deploy.version=${project-version}

是的,正如您提到的,我认为在这里使用 --image-url 标志是一个不错的选择。

指定自定义运行时。 在本地构建镜像,标记它,并将其推送到 Google Container Registry (GCR) 然后,部署您的服务,指定自定义服务文件,并使用 --image-url 选项在 GCR 上指定远程图像。

这是一个在共享相同代码的 2 个服务中完成不同入口点的示例: ...这是假设正在使用 "flex" 而不是 "standard" 应用程序引擎产品。

假设您有一个:名为 my-proj 的项目 使用不重要的默认服务 第二个服务称为 queue-processor,它使用同一目录中的大部分相同代码。 为它创建一个单独的 docker 文件,名为 QueueProcessorDockerfile 和一个单独的 app.yaml 调用 queue-processor-app.yaml 告诉 google 应用引擎我想要发生什么。

QueueProcessorDockerfile

FROM node:10
# Create app directory
WORKDIR /usr/src/app
COPY package.json ./
COPY yarn.lock ./
RUN npm install -g yarn
RUN yarn
# Bundle app source
COPY . .
CMD [ "yarn", "process-queue" ]

*我的 package.json 中当然有一个 "process-queue" 脚本 queue-processor-app.yaml

runtime: custom
env: flex
... other stuff...
...
  1. 构建并标记 docker 图像 在此处查看 google 的指南 -> https://cloud.google.com/container-registry/docs/pushing-and-pulling docker build -t eu.gcr.io/my-proj/queue-processor -f QueueProcessorDockerfile .
  2. 推送到 GCR docker 推送 eu.gcr.io/my-proj/queue-processor
  3. 部署服务,指定 google 应该使用哪个 yaml 配置文件,以及你推送的图像 url gcloud app deploy queue-processor-app.yaml --image-url eu.gcr.io/my-proj/queue-processor