简体   繁体   English

Dockerfile 和 Docker 使用 PSQL DB 为 NestJS 应用程序编写,其中运行时需要环境变量

[英]Dockerfile and Docker Compose for NestJS app with PSQL DB where env vars are expected at runtime

I'm Dockerizing a simple Node/JS (NestJS -- but I don't think that matters for this question) web service and have some questions.我正在 Dockerizing 一个简单的 Node/JS(NestJS——但我认为这对这个问题并不重要)web 服务并有一些问题。 This service talks to a Postgres DB.该服务与 Postgres DB 对话。 I would like to write a Dockerfile that can be used to build an image of the service (let's call it my-service ) and then write a docker-compose.yml that defines a service for the Postgres DB as well as a service for my-service that uses it.我想编写一个Dockerfile可用于构建服务的映像(我们称之为my-service ),然后编写一个docker-compose.yml定义 Postgres DB 的服务以及my-service使用它。 That way I can build images of my-service but also have a Docker Compose config for running the service and its DB at the same time together.这样我可以构建my-service的映像,但也有一个 Docker Compose 配置,用于同时运行服务及其数据库。 I think that's the way to do this (keep me honest though.).认为这是做到这一点的方法(但请保持诚实。)。 Kubernetes is not an option for me, just FYI. Kubernetes 对我来说不是一个选项,仅供参考。

The web service has a top-level directory structure like so: web 服务的顶级目录结构如下:

my-service/
    .env
    package.json
    package-lock.json
    src/
    <lots of other stuff>

Its critical to note that in its present, non-containerized form, you have to set several environment variables ahead of time, including the Postgres DB connection info (host, port, database name, username, password, etc.).需要注意的是,在目前的非容器化形式中,您必须提前设置几个环境变量,包括 Postgres DB 连接信息(主机、端口、数据库名称、用户名、密码等)。 The application code fetches the values of these env vars at runtime and uses them to connect to Postgres.应用程序代码在运行时获取这些环境变量的值并使用它们连接到 Postgres。

So, I need a way to write a Dockerfile and docker-compose.yml such that:所以,我需要一种方法来编写Dockerfiledocker-compose.yml ,这样:

  • if I'm just running a container of the my-service image by itself, and want to tell it to connect to any arbitrary Postgres DB, I can pass those env vars in as (ideally) runtime arguments on the Docker CLI command (however remember the app expects them to be set as env vars);如果我只是自己运行my-service映像的容器,并想告诉它连接到任意 Postgres DB,我可以在 Docker CLI 命令上将这些环境变量作为(理想情况下)运行时 arguments 传递(但是请记住应用程序希望将它们设置为环境变量); and
  • if I'm spinning up the my-service and its Postgres together via the Docker Compose file, I need to also specify those as runtime args in the Docker Compose CLI, then Docker Compose needs to pass them on to the container's run arguments, and then the container needs to set them as env vars for web service to use if I'm spinning up the my-service and its Postgres together via the Docker Compose file, I need to also specify those as runtime args in the Docker Compose CLI, then Docker Compose needs to pass them on to the container's run arguments, and然后容器需要将它们设置为 web 服务使用的环境变量

Again, I think this is the correct way to go, but keep me honest!同样,我认为这是 go 的正确方法,但请保持诚实!

So my best attempt -- a total WIP so far -- looks like this:所以我最好的尝试——到目前为止的总在制品——看起来像这样:

Dockerfile

FROM node:18

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

# creates "dist" to run out of
RUN npm run build

# ideally the env vars are already set at this point via
## docker CLI arguments, so nothing to pass in here (???)
CMD [ "node", "dist/main.js" ]

docker-compose.yml

version: '3.7'

services:
  postgres:
    container_name: postgres
    image: postgres:14.3
    environment:
      POSTGRES_PASSWORD: ${psql.password}
      POSTGRES_USER: ${psql.user}
      POSTGRES_DB: my-service-db
      PG_DATA: /var/lib/postgresql2/data
    ports:
      - 5432:5432
    volumes:
      - pgdata:/var/lib/postgresql2/data
  my-service:
    container_name: my-service
    image: ???  anyway to say "build whats in the repo?"
    environment:
      ??? do I need to set anything here so it gets passed to the my-service
          container as env vars?
volumes:
  pgdata:

Can anyone help nudge me over the finish line here?谁能帮我推过终点线? Thanks in advance!提前致谢!

??? ??? do I need to set anything here so it gets passed to the my-service container as env vars?我是否需要在此处设置任何内容以便将其作为环境变量传递给 my-service 容器?

Yes, you should pass the variables there.是的,您应该在那里传递变量。 This is a principle of 12 factor design这是12因素设计的原则

need to also specify those as runtime args in the Docker Compose CLI, then Docker Compose needs to pass them on to the container's run arguments还需要在 Docker Compose CLI 中将它们指定为运行时参数,然后 Docker Compose 需要将它们传递给容器的运行 arguments

If you don't put them directly in the YAML, will this option work for you?如果您不直接将它们放在 YAML 中,此选项是否适合您?

docker-compose --env-file app.env up

Ideally, you also put理想情况下,你也把

depends_on:
  postgres

So that when you start your service, the database will also start up.这样当您启动服务时,数据库也将启动。

If you want to connect to a different database instance, then you can either create a separate compose file without that database, or use a different set of variables (written out, or using env_file , as mentioned)如果要连接到不同的数据库实例,则可以在没有该数据库的情况下创建单独的 compose 文件,或使用不同的变量集(如前所述,写出或使用env_file

Or you can use NPM dotenv or config packages and set different .env files for different database environments, based on other variables, such as NODE_ENV , at runtime.或者您可以使用 NPM dotenvconfig包,并在运行时根据其他变量(例如NODE_ENV )为不同的数据库环境设置不同的.env文件。

??? ??? anyway to say "build whats in the repo?"无论如何要说“在回购中构建什么?”

Use build instead of image directive.使用build而不是image指令。

Kubernetes is not an option for me, just FYI Kubernetes 不适合我,仅供参考

You could use Minikube instead of Compose... Doesn't really matter, but kompose exists to convert a Docker Compose into k8s resources.可以使用 Minikube 代替 Compose ... 没关系,但kompose存在将 Docker Compose 转换为 k8s 资源。

Your Dockerfile is correct.您的Dockerfile是正确的。 You can specify the environment variables while doing docker run like this:您可以在执行docker run时指定环境变量,如下所示:

docker run --name my-service -it <image> -e PG_USER='user' -e PG_PASSWORD='pass'
  -e PG_HOST='dbhost' -e PG_DATABASE='dbname' --expose <port>

Or you can specify the environment variables with the help of .env file.或者您可以在.env文件的帮助下指定环境变量。 Let's call it app.env .我们称之为app.env Its content would be:它的内容是:

PG_USER=user
PG_PASSWORD=pass
PG_DATABASE=dbname
PG_HOST=dbhost
OTHER_ENV_VAR1=someval
OTHER_ENV_VAR2=anotherval

Now instead of specifying multiple -e options to docker run command, you can simply tell the name of the file from where the environment variables need to be picked up.现在,无需为docker run命令指定多个-e选项,您只需告知需要从何处获取环境变量的文件名。

docker run --name my-service -it <image> --env-file app.env --expose <port>

In order to run postgres and your service with a single docker compose command, a few modifications need to be done in your docker-compose.yml .为了使用单个 docker compose 命令运行 postgres 和您的服务,需要在docker-compose.yml中进行一些修改。 Let's first see the full YAML .我们先来看看完整的YAML

version: '3.7'

services:
  postgres:
    container_name: postgres
    image: postgres:14.3
    environment:
      POSTGRES_PASSWORD: $PG_PASSWORD
      POSTGRES_USER: $PG_USER
      POSTGRES_DB: my-service-db
      PG_DATA: /var/lib/postgresql2/data
    ports:
      - 5432:5432
    volumes:
      - pgdata:/var/lib/postgresql2/data
  my-service:
    container_name: my-service
    build: .   #instead of image directive, use build to tell docker what folder to build
    environment:
      PG_USER: $PG_USER
      PG_PASSWORD: $PG_PASSWORD
      PG_HOST: postgres   #note the name of the postgres service in compose yaml
      PG_DATABASE: my-service-db
      OTHER_ENV_VAR1: $OTHER_ENV_VAR1
      OTHER_ENV_VAR2: $OTHER_ENV_VAR2
    depends_on:
      postgres
volumes:
  pgdata:

Now you can use docker compose up command to run the services.现在您可以使用docker compose up命令来运行服务。 If you wish to build the my-service container each time you can pass an optional argument --build like this: docker compose up --build .如果您希望每次都构建my-service容器,您可以像这样传递一个可选参数--builddocker compose up --build

In order to pass the environment variables from the CLI, there's only one way which is by the use of .env file.为了从 CLI 传递环境变量,只有一种方法是使用.env文件。 In your case of docker-compose.yml the app.env would look like:在您的app.env的情况下, docker-compose.yml看起来像:

PG_USER=user
PG_PASSWORD=pass
#PG_DATABASE=dbname   #not required as you're using 'my-service-db' as db name in compose file
#PG_HOST=dbhost       #not required as service name of postgres in compose file is being used as db host
OTHER_ENV_VAR1=someval
OTHER_ENV_VAR2=anotherval

Passing this app.env file using docker compose CLI command would look like this:使用 docker compose CLI 命令传递此app.env文件如下所示:

docker compose --env-file app.env up --build

PS: If you're building your my-service each time just for the code changes to reflect in the docker container, you could make use of bind mount instead. PS:如果您每次构建my-service只是为了代码更改以反映在 docker 容器中,您可以改用绑定挂载。 The updated docker-compose.yml in that case would look like this:在这种情况下,更新后的docker-compose.yml如下所示:

version: '3.7'

services:
  postgres:
    container_name: postgres
    image: postgres:14.3
    environment:
      POSTGRES_PASSWORD: $PG_PASSWORD
      POSTGRES_USER: $PG_USER
      POSTGRES_DB: my-service-db
      PG_DATA: /var/lib/postgresql2/data
    ports:
      - 5432:5432
    volumes:
      - pgdata:/var/lib/postgresql2/data
  my-service:
    container_name: my-service
    build: .
    volumes:
      - .:/usr/src/app    #note the use of volumes here
    environment:
      PG_USER: $PG_USER
      PG_PASSWORD: $PG_PASSWORD
      PG_HOST: postgres
      PG_DATABASE: my-service-db
      OTHER_ENV_VAR1: $OTHER_ENV_VAR1
      OTHER_ENV_VAR2: $OTHER_ENV_VAR2
    depends_on:
      postgres
volumes:
  pgdata:

This way, you don't need to run docker compose build each time, making a code change in the source folder would get reflected in the docker container.这样,您不需要每次都运行 docker compose build,在源文件夹中进行代码更改将反映在 docker 容器中。

You just need to add path of your docker file in to build parameter in docker-compose.yaml file and all the environment variables in environment您只需在 docker-compose.yaml 文件和环境中的所有环境变量中添加 docker 文件的路径即可构建参数

version: '3.7'

services:
  postgres:
    container_name: postgres
    image: postgres:14.3
    environment:
      POSTGRES_PASSWORD: ${psql.password}
      POSTGRES_USER: ${psql.user}
      POSTGRES_DB: my-service-db
      PG_DATA: /var/lib/postgresql2/data
    ports:
      - 5432:5432
    volumes:
      - pgdata:/var/lib/postgresql2/data
  my-service:
    container_name: my-service
    image: path_to_your_dockerfile
    environment:
      your_environment_variables_here
          container as env vars?
volumes:
  pgdata

I am guessing that you have folder structure like this我猜你有这样的文件夹结构

project_folder/
               docker-compose.yaml
               my-service/
                           Dockerfile
                          .env
                           package.json
                           package-lock.json
                           src/
                           <lots of other stuff>

and your.env contains following并且 your.env 包含以下内容

API_PORT=8082
Environment_var1=Environment_var1_value
Environment_var2=Environment_var2_value 

So in your case your docker-compose file should look like this因此,在您的情况下,您的 docker-compose 文件应如下所示

version: '3.7'

services:
  postgres:
    container_name: postgres
    image: postgres:14.3
    environment:
      POSTGRES_PASSWORD: ${psql.password}
      POSTGRES_USER: ${psql.user}
      POSTGRES_DB: my-service-db
      PG_DATA: /var/lib/postgresql2/data
    ports:
      - 5432:5432
    volumes:
      - pgdata:/var/lib/postgresql2/data
  my-service:
    container_name: my-service
    image: ./my-service/
    environment:
      - API_PORT=8082
      - Environment_var1=Environment_var1_value
      - Environment_var2=Environment_var2_value 
volumes:
  pgdata

FYI: for this docker configuration your database connection host should be postgres (as per service name) not localhost and your仅供参考:对于这个 docker 配置,您的数据库连接主机应该是postgres (根据服务名称)而不是localhost和您的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Docker compose is using the env which was built by Dockerfile, instead of using env_file located in docker-compose.yml directory because of webpack - Docker compose is using the env which was built by Dockerfile, instead of using env_file located in docker-compose.yml directory because of webpack 如何运行开发和生产nestjs app docker docker-compose - How to run development and production nestjs app docker docker-compose 环境变量来更改project.json中的应用程序名称并设置运行时变量? - Env vars to change app name in project.json and set runtime vars? 基于构建 ARG 有条件地在 Dockerfile 中设置 ENV 变量 - Conditionally setting ENV vars in Dockerfile based on build ARG 如何将Dockerfile转换为docker compose图像? - How to convert a Dockerfile to a docker compose image? 如何在没有 Dockerfile 的情况下设置 Docker 组合? - How to setup Docker Compose without a Dockerfile? 使用 SSH 代理与 Docker 组合和 Dockerfile - Using SSH agent with Docker Compose and Dockerfile 如何使用环境变量在 Elastic Beanstalk EB 上运行 sequelize db:migrate? 如何在容器命令中访问 .env vars? - How to run sequelize db:migrate on Elastic Beanstalk EB with env vars? How to access .env vars in container commands? Docker Compose: .env: no such file or directory / NodeJS - Docker Compose: .env: no such file or directory / NodeJS docker-compose - NODE_ENV 不适用 - docker-compose - NODE_ENV not applying
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM