docker-compose secrets MYSQL_ROOT_PASSWORD_FILE work correctly but DB_PASSWORD result empty string

huangapple go评论116阅读模式
英文:

docker-compose secrets MYSQL_ROOT_PASSWORD_FILE work correctly but DB_PASSWORD result empty string

问题

MYSQL_ROOT_PASSWORD_FILE在数据库容器中正常工作,但DB_PASSWORD为空字符串

在我的项目中,我使用React作为前端,使用Fiber框架的Golang作为后端,MySQL作为数据库。

当我在Dockerfile中设置环境变量时,它可以正常工作。但是当我使用docker-compose secrets时,在数据库容器中可以正常工作,但在后端容器中,环境变量的值为空字符串。

dockercompose.yml

  1. version: '2.17.3'
  2. services:
  3. backend:
  4. container_name: app-backend
  5. image: app-backend:private
  6. build:
  7. context: ./server/.
  8. dockerfile: Dockerfile.private
  9. secrets:
  10. - db_password
  11. - db_name
  12. - jwt_secret_key
  13. - mailer_password
  14. - mailer_username
  15. environment:
  16. - DB_HOST=my-database
  17. - DB_PORT=3306
  18. - DB_USER=root
  19. - DB_PASSWORD_FILE=/run/secrets/db_password
  20. - DB_NAME_FILE=/run/secrets/db_name
  21. # Leave SERVER_HOST BLANK. Info: https://stackoverflow.com/a/61047889
  22. - SERVER_HOST=
  23. - SERVER_PORT=8080
  24. - WEBSITE_HOST=localhost:3000
  25. - JWT_SECRET_KEY_FILE=/run/secrets/jwt_secret_key
  26. - MAILER_HOST=smtp.gmail.com
  27. - MAILER_PORT=587
  28. - MAILER_USERNAME_FILE=/run/secrets/mailer_username
  29. - MAILER_PASSWORD_FILE=/run/secrets/mailer_password
  30. - ALLOW_ORIGINS=http://localhost:3000
  31. ports:
  32. - 8000:8080
  33. user: nonroot:nonroot
  34. networks:
  35. - my-network
  36. database:
  37. container_name: app-database
  38. image: mysql
  39. build:
  40. dockerfile: ./server/Dockerfile.database
  41. secrets:
  42. - db_root_password
  43. environment:
  44. - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_root_password
  45. ports:
  46. - 3307:3306
  47. command: --default-authentication-plugin=mysql_native_password
  48. restart: unless-stopped
  49. networks:
  50. - my-network
  51. networks:
  52. my-network:
  53. secrets:
  54. db_root_password:
  55. file: ./secrets/db_root_password.txt
  56. db_password:
  57. file: ./secrets/db_password.txt
  58. db_name:
  59. file: ./secrets/db_name.txt
  60. jwt_secret_key:
  61. file: ./secrets/jwt_secret_key.txt
  62. mailer_password:
  63. file: ./secrets/mailer_password.txt
  64. mailer_username:
  65. file: ./secrets/mailer_username.txt

Dockerfile.private

  1. # syntax=docker/dockerfile:1
  2. ##
  3. ## Build the application from source
  4. ##
  5. FROM golang:1.20.4-bullseye AS build-stage
  6. WORKDIR /app
  7. COPY go.mod go.sum ./
  8. RUN go mod download && go mod verify
  9. COPY . ./
  10. RUN CGO_ENABLED=0 GOOS=linux go build -o main main.go
  11. ##
  12. ## Deploy the application binary into a lean image
  13. ##
  14. FROM gcr.io/distroless/base-debian11 AS build-release-stage
  15. WORKDIR /app
  16. COPY --from=build-stage /app/main .
  17. EXPOSE 8080
  18. USER nonroot:nonroot
  19. ENTRYPOINT ["/app/main"]

Dockerfile.database

  1. # database
  2. FROM mysql
  3. EXPOSE 3306
  4. CMD ["--default-authentication-plugin=mysql_native_password"]

构建脚本

docker-compose up -d --build

我已经检查了mysql数据库中的MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_root_password,它可以正常工作。我可以连接到数据库,但在后端中,Docker桌面日志显示为空字符串。

  1. ┌───────────────────────────────────────────────────┐
  2. Fiber v2.45.0
  3. http://127.0.0.1:8080 │
  4. (bound on host 0.0.0.0 and port 8080)
  5. Handlers ............ 49 Processes ........... 1
  6. Prefork ....... Disabled PID ................. 1
  7. └───────────────────────────────────────────────────┘
  8. 2023/05/22 22:21:30 Try connecting to database: %w root:@tcp(nf-theater-database:3306)/?parseTime=true

这是我的Golang连接代码:

  1. package database
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. func Connect() *sql.DB {
  9. dbUser := os.Getenv("DB_USER")
  10. dbPassword := os.Getenv("DB_PASSWORD")
  11. dbHost := os.Getenv("DB_HOST")
  12. dbPort := os.Getenv("DB_PORT")
  13. dbName := os.Getenv("DB_NAME")
  14. connString := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", dbUser, dbPassword, dbHost, dbPort, dbName)
  15. log.Println("Try connecting to database: %w", connString)
  16. // Open database connection
  17. db, err := sql.Open("mysql", connString)
  18. if err != nil {
  19. fmt.Println(err.Error())
  20. }
  21. return db
  22. }

我尝试将docker-compose的第一行版本从version: '2.17.3'更改为version: '3.8',但结果仍然相同。

我不明白为什么它不起作用。如果不必要,我不想切换到Swarm。我该如何解决这个问题?

英文:

MYSQL_ROOT_PASSWORD_FILE work correctly but DB_PASSWORD result empty string

In my project. I use react as frontend, golang with fiber framework as backend and mysql as database.

It work fine when I set ENV in Dockerfile. but when I work with docker-compose secrets. In database container work correctly but in backend container. The environment variable result empty string,

dockercompose.yml

  1. version: '2.17.3'
  2. backend:
  3. container_name: app-backend
  4. image: app-backend:private
  5. build:
  6. context: ./server/.
  7. dockerfile: Dockerfile.private
  8. secrets:
  9. - db_password
  10. - db_name
  11. - jwt_secret_key
  12. - mailer_password
  13. - mailer_username
  14. environment:
  15. - DB_HOST=my-database
  16. - DB_PORT=3306
  17. - DB_USER=root
  18. - DB_PASSWORD_FILE=/run/secrets/db_password
  19. - DB_NAME_FILE=/run/secrets/db_name
  20. # Leave SERVER_HOST BLANK. Info: https://stackoverflow.com/a/61047889
  21. - SERVER_HOST=
  22. - SERVER_PORT=8080
  23. - WEBSITE_HOST=localhost:3000
  24. - JWT_SECRET_KEY_FILE=/run/secrets/jwt_secret_key
  25. - MAILER_HOST=smtp.gmail.com
  26. - MAILER_PORT=587
  27. - MAILER_USERNAME_FILE=/run/secrets/mailer_username
  28. - MAILER_PASSWORD_FILE=/run/secrets/mailer_password
  29. - ALLOW_ORIGINS=http://localhost:3000
  30. ports:
  31. - 8000:8080
  32. user: nonroot:nonroot
  33. networks:
  34. - my-network
  35. database:
  36. container_name: app-database
  37. image: mysql
  38. build:
  39. dockerfile: ./server/Dockerfile.database
  40. secrets:
  41. - db_root_password
  42. environment:
  43. - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_root_password
  44. ports:
  45. - 3307:3306
  46. command: --default-authentication-plugin=mysql_native_password
  47. restart: unless-stopped
  48. networks:
  49. - my-network
  50. networks:
  51. my-network:
  52. secrets:
  53. db_root_password:
  54. file: ./secrets/db_root_password.txt
  55. db_password:
  56. file: ./secrets/db_password.txt
  57. db_name:
  58. file: ./secrets/db_name.txt
  59. jwt_secret_key:
  60. file: ./secrets/jwt_secret_key.txt
  61. mailer_password:
  62. file: ./secrets/mailer_password.txt
  63. mailer_username:
  64. file: ./secrets/mailer_username.txt

Dockerfile.private

  1. # syntax=docker/dockerfile:1
  2. ##
  3. ## Build the application from source
  4. ##
  5. FROM golang:1.20.4-bullseye AS build-stage
  6. WORKDIR /app
  7. COPY go.mod go.sum ./
  8. RUN go mod download && go mod verify
  9. COPY . ./
  10. RUN CGO_ENABLED=0 GOOS=linux go build -o main main.go
  11. ##
  12. ## Deploy the application binary into a lean image
  13. ##
  14. FROM gcr.io/distroless/base-debian11 AS build-release-stage
  15. WORKDIR /app
  16. COPY --from=build-stage /app/main .
  17. EXPOSE 8080
  18. USER nonroot:nonroot
  19. ENTRYPOINT ["/app/main"]

Dockerfile.database

  1. # database
  2. FROM mysql
  3. EXPOSE 3306
  4. CMD ["--default-authentication-plugin=mysql_native_password"]

build script

docker-compose up -d --build

I've check MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_root_password in mysql database. It work correctly. I can connect to database. but in backend. In docker-desktop logs show it have empty string

  1. ┌───────────────────────────────────────────────────┐
  2. Fiber v2.45.0
  3. http://127.0.0.1:8080 │
  4. (bound on host 0.0.0.0 and port 8080)
  5. Handlers ............ 49 Processes ........... 1
  6. Prefork ....... Disabled PID ................. 1
  7. └───────────────────────────────────────────────────┘
  8. 2023/05/22 22:21:30 Try connecting to database: %w root:@tcp(nf-theater-database:3306)/?parseTime=true

Here my golang connection code

  1. package database
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "log"
  6. "os"
  7. )
  8. func Connect() *sql.DB {
  9. dbUser := os.Getenv("DB_USER")
  10. dbPassword := os.Getenv("DB_PASSWORD")
  11. dbHost := os.Getenv("DB_HOST")
  12. dbPort := os.Getenv("DB_PORT")
  13. dbName := os.Getenv("DB_NAME")
  14. connString := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", dbUser, dbPassword, dbHost, dbPort, dbName)
  15. log.Println("Try connecting to database: %w", connString)
  16. // Open database connection
  17. db, err := sql.Open("mysql", connString)
  18. if err != nil {
  19. fmt.Println(err.Error())
  20. }
  21. return db
  22. }

I've try to change version in first line of docker-compose from version: '2.17.3' to version: '3.8' but result was the same

I don't understand why it's don't work. I don't want to switch to swarm if it don't have to. How can I fix this?

答案1

得分: 0

MYSQL docker-entrypoint.sh 检查环境变量 MYSQL_ROOT_PASSWORD_FILE,如果存在,则将变量中指定的文件内容加载到环境变量 MYSQL_ROOT_PASSWORD 中(然后在脚本的其他地方将其用作密码)。

因此,没有特殊处理以 _FILE 结尾的变量;容器中的某个组件需要检查该变量并从文件中加载数据。

你的 docker-compose.yml 设置了变量 DB_PASSWORD_FILE 并直接运行应用程序(ENTRYPOINT ["/app/main"])。然后你尝试读取 DB_PASSWORDdbPassword := os.Getenv("DB_PASSWORD"));这将为空,因为你没有设置该环境变量。

你可以添加一个类似于 MYSQL 容器中使用的脚本,或者直接读取设置的变量,例如:

  1. dbPasswordFile := os.Getenv("DB_PASSWORD_FILE")
  2. dbPassword, err := os.ReadFile(dbPasswordFile)

注意:你应该检查空变量并处理任何错误

英文:

The MYSQL docker-entrypoint.sh checks for the environment variable MYSQL_ROOT_PASSWORD_FILE and, if present, loads the contents of the file named in the variable into the environmental variable MYSQL_ROOT_PASSWORD (which is then used elsewhere in the script as the password).

So there is no special handling of variables ending with _FILE; something in the container needs to check for the variable and load the data from the file.

Your docker-compose.yml sets the variable DB_PASSWORD_FILE and runs your application directly (ENTRYPOINT ["/app/main"]). You then attempt to read DB_PASSWORD (dbPassword := os.Getenv("DB_PASSWORD")); this will be empty because you have not set that environmental variable.

You could add a script, similar to that used in the MYSQL container, or just read the variable as set e.g.

  1. dbPasswordFile := os.Getenv("DB_PASSWORD_FILE")
  2. dbPassword, err := os.ReadFile(dbPasswordFile)

Note: You should probably check for a blank variable and handle any errors

huangapple
  • 本文由 发表于 2023年5月23日 07:06:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76310374.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定