This is most likely due to my lack of knowledge around Docker, so I probably just need a theoretical answer but I can post some code if needed.
So, I have a containerized project that connects to a managed database on Digital Ocean through a public network connection and SSL is required so I have that configured. When I run it locally with:
docker compose build
docker compose up
everything looks fine and I can see that it connects to the DB. Then I push the new images to docker hub with:
docker compose push
and reference those images in my docker-compose.yml:
image: <myDockerID>/<imagename>
I've checked Docker hub to confirm that the images are being updated when pushing and also deleted them to make sure they were the right images being uploaded.
In my root directory I have the key files:
From what I've read, everything looks good.
From my understanding, I should now be able to copy/paste the docker-compose file in any directory on any machine and run docker compose up
(this might be where I misunderstand). However, when I try this, I get an SSL error.
For example, in a new directory containing only the docker-compose.yml, I would clear out old stuff then run fresh:
docker compose down -v --rmi all --remove-orphans
docker compose up
and it fetches new images and everything looks pretty good except that now I get:
[TypeOrmModule] Unable to connect to the database. Retrying (2)...
worker | Error: The server does not support SSL connections
worker | at Socket.<anonymous> (/usr/src/app/node_modules/pg/lib/connection.js:77:37)
worker | at Object.onceWrapper (node:events:628:26)
worker | at Socket.emit (node:events:513:28)
worker | at addChunk (node:internal/streams/readable:324:12)
worker | at readableAddChunk (node:internal/streams/readable:297:9)
worker | at Readable.push (node:internal/streams/readable:234:10)
worker | at TCP.onStreamRead (node:internal/stream_base_commons:190:23)
So, my question is why doesn't this error present itself in the project directory? Is this error referring to the DB not supporting SSL connection (it does)? Does docker require more than just the docker-compose.yml file to run correctly?
Here is my Dockerfile:
FROM node:18.16.0-alpine
WORKDIR /usr/src/app
COPY package.json ./
COPY yarn.lock ./
RUN yarn --production
COPY . .
RUN yarn build
Here is my docker-compose.yml:
version: "3.8"
networks:
app-net:
driver: bridge
volumes:
server_data: {}
worker_data: {}
postgres_data: {}
services:
######################################################################################
server:
container_name: server
build:
context: .
dockerfile: Dockerfile
image: <dockhubID>/backend2-server
ports:
- 3001:3001
command: ["yarn", "start:server"]
volumes:
- server_data:/usr/src/app
networks:
- app-net
environment:
DB_HOST: ${DB_HOST}
DB_PORT: ${DB_PORT}
DB_NAME: ${DB_NAME}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
DB_CA_CERT_PATH: ${DB_CA_CERT_PATH}
worker:
container_name: worker
build:
context: .
dockerfile: Dockerfile
image: <dockerhubID>/backend2-worker
command: ["yarn", "start:worker"]
volumes:
- worker_data:/usr/src/app
expose:
- 4000
networks:
- app-net
environment:
DB_HOST: ${DB_HOST}
DB_PORT: ${DB_PORT}
DB_NAME: ${DB_NAME}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
DB_CA_CERT_PATH: ${DB_CA_CERT_PATH}
Any help is greatly appreciated!
I've seen the following questions but wasn't able to answer the questions that pertain to my situation:
UPDATE: After adding the missing environment variable to the docker-compose.yml file, I'm seeing an error that makes me think I didn't set the variable correctly:
node:internal/fs/utils:347
worker | throw err;
worker | ^
worker |
worker | Error: ENOENT: no such file or directory, open
worker | at Object.openSync (node:fs:601:3)
worker | at Object.readFileSync (node:fs:469:35)
worker | at Object.<anonymous> (/usr/src/app/dist/vendure-config.js:62:30)
worker | at Module._compile (node:internal/modules/cjs/loader:1254:14)
worker | at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
worker | at Module.load (node:internal/modules/cjs/loader:1117:32)
worker | at Module._load (node:internal/modules/cjs/loader:958:12)
worker | at Module.require (node:internal/modules/cjs/loader:1141:19)
worker | at require (node:internal/modules/cjs/helpers:110:18)
worker | at Object.<anonymous> (/usr/src/app/dist/index-worker.js:4:26) {
worker | errno: -2,
worker | syscall: 'open',
worker | code: 'ENOENT'
worker | }
I also see this warning now:
WARN[0000] The "DB_CA_CERT_PATH" variable is not set. Defaulting to a blank string.
The variable is set in .env
as:
DB_CA_CERT_PATH=/usr/src/app/ca-certificate.crt
Since the Dockerfile's workspace is set to /usr/src/app
, I assume the path should be correct. I also assume that .env
is copied over when COPY . .
is ran, but I could be mistaken. Just to reiterate, I'm focusing on the case where I copy the docker-compose.yml file into an empty directory. Running the container in the original directory still works fine.
Thanks again for the help!
I will try to summarize the comments by Alex D. and me:
ca-certificate.crt
is used for the SSL connection, and that your docker-compose.yml
is where you are referencing this certificate and the path in that file might be broken.process.env.DB_CA_CERT_PATH
. However, it was unclear how you are setting this variable in the container, since it was not present in the docker-compose.yml
or Dockerfile
.docker-compose.yml
file, which in turn references a "local" environment variable defined in an .env
file, which needs to be present alongside the docker-compose.yml
.As you pointed out, the way you are currently defining your environment variables in the docker-compose.yml
(e.g. DB_CA_CERT_PATH: ${DB_CA_CERT_PATH}
), you actually are only passing your "local" environment variables on the host to that file, which are then passed into the docker container. For this reason, you also need the .env
file alongside the docker-compose.yml
file.
If you only want to use "a single docker-compose.yml
" file without the local .env
file, you can just defined the environment variables directly in docker-compose.yml
:
server:
...
environment:
DB_CA_CERT_PATH=/usr/src/app/ca-certificate.crt
If you wanted to have a self-contained image, you could, again, use a .env
file which is copied to the image, or define these environment variables in your Dockerfile
with the ENV
instruction.