繁体   English   中英

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

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

我正在 Dockerizing 一个简单的 Node/JS(NestJS——但我认为这对这个问题并不重要)web 服务并有一些问题。 该服务与 Postgres DB 对话。 我想编写一个Dockerfile可用于构建服务的映像(我们称之为my-service ),然后编写一个docker-compose.yml定义 Postgres DB 的服务以及my-service使用它。 这样我可以构建my-service的映像,但也有一个 Docker Compose 配置,用于同时运行服务及其数据库。 认为这是做到这一点的方法(但请保持诚实。)。 Kubernetes 对我来说不是一个选项,仅供参考。

web 服务的顶级目录结构如下:

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

需要注意的是,在目前的非容器化形式中,您必须提前设置几个环境变量,包括 Postgres DB 连接信息(主机、端口、数据库名称、用户名、密码等)。 应用程序代码在运行时获取这些环境变量的值并使用它们连接到 Postgres。

所以,我需要一种方法来编写Dockerfiledocker-compose.yml ,这样:

  • 如果我只是自己运行my-service映像的容器,并想告诉它连接到任意 Postgres DB,我可以在 Docker CLI 命令上将这些环境变量作为(理想情况下)运行时 arguments 传递(但是请记住应用程序希望将它们设置为环境变量);
  • 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 服务使用的环境变量

同样,我认为这是 go 的正确方法,但请保持诚实!

所以我最好的尝试——到目前为止的总在制品——看起来像这样:

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:

谁能帮我推过终点线? 提前致谢!

??? 我是否需要在此处设置任何内容以便将其作为环境变量传递给 my-service 容器?

是的,您应该在那里传递变量。 这是12因素设计的原则

还需要在 Docker Compose CLI 中将它们指定为运行时参数,然后 Docker Compose 需要将它们传递给容器的运行 arguments

如果您不直接将它们放在 YAML 中,此选项是否适合您?

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

理想情况下,你也把

depends_on:
  postgres

这样当您启动服务时,数据库也将启动。

如果要连接到不同的数据库实例,则可以在没有该数据库的情况下创建单独的 compose 文件,或使用不同的变量集(如前所述,写出或使用env_file

或者您可以使用 NPM dotenvconfig包,并在运行时根据其他变量(例如NODE_ENV )为不同的数据库环境设置不同的.env文件。

??? 无论如何要说“在回购中构建什么?”

使用build而不是image指令。

Kubernetes 不适合我,仅供参考

可以使用 Minikube 代替 Compose ... 没关系,但kompose存在将 Docker Compose 转换为 k8s 资源。

您的Dockerfile是正确的。 您可以在执行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>

或者您可以在.env文件的帮助下指定环境变量。 我们称之为app.env 它的内容是:

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

现在,无需为docker run命令指定多个-e选项,您只需告知需要从何处获取环境变量的文件名。

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

为了使用单个 docker compose 命令运行 postgres 和您的服务,需要在docker-compose.yml中进行一些修改。 我们先来看看完整的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:

现在您可以使用docker compose up命令来运行服务。 如果您希望每次都构建my-service容器,您可以像这样传递一个可选参数--builddocker compose up --build

为了从 CLI 传递环境变量,只有一种方法是使用.env文件。 在您的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

使用 docker compose CLI 命令传递此app.env文件如下所示:

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

PS:如果您每次构建my-service只是为了代码更改以反映在 docker 容器中,您可以改用绑定挂载。 在这种情况下,更新后的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:

这样,您不需要每次都运行 docker compose build,在源文件夹中进行代码更改将反映在 docker 容器中。

您只需在 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

我猜你有这样的文件夹结构

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

并且 your.env 包含以下内容

API_PORT=8082
Environment_var1=Environment_var1_value
Environment_var2=Environment_var2_value 

因此,在您的情况下,您的 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

仅供参考:对于这个 docker 配置,您的数据库连接主机应该是postgres (根据服务名称)而不是localhost和您的

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM