DRY docker-compose - dry

I'm trying to find a more DRY way to use docker-compose env.
docker-compose-base.yml
base:
image: reactjs_web
volumes:
- src:/reactjs/src
- bin/server:/reactjs/bin/server
- config:/reactjs/config
docker-compose-prod.yml
svr:
extends:
file: docker-compose-base.yml
service: base
command: npm run prod:deploy
ports:
- "8081:8081"
environment:
NODE_ENV: production
PORT: "8081"
CLTPORT: "8082"
clt:
extends:
file: docker-compose-base.yml
service: base
command: npm run prod:deploy:clientside
ports:
- "8082:8082"
environment:
NODE_ENV: production
PORT: "8082"
The ports and the env port are equals
Is there a way to reference the clt port to the svr container ?

Docker Environment File
Use a .env file and reference it in both containers. This will ensure you only need to store these settings in a single location.
Compose supports declaring default environment variables in an environment file named .env placed in the folder docker-compose command is executed from (current working directory).
Compose expects each line in an env file to be in VAR=VAL format. Lines beginning with # (i.e. comments) are ignored, as are blank lines.
Compose File Integration:
env_file: .env
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
Docker Compose File Reference - env_file
Docker Compose Environment File Documentation

You can use environment variable inside docker-compose.
svr:
extends:
file: docker-compose-base.yml
service: base
command: npm run prod:deploy
ports:
- ${CLTPORT}:${PORT}
environment:
NODE_ENV: production
clt:
extends:
file: docker-compose-base.yml
service: base
command: npm run prod:deploy:clientside
ports:
- ${CLTPORT2}:${PORT2}
environment:
NODE_ENV: production
run docker-compose like:
CLTPORT=8082 PORT=8081 CLTPORT2=8081 PORT2=8082 docker-compose -f docker-compose-prod.yml up
Of course change your port variables as you need.

You can reference an environment variable to solve this
https://github.com/docker/compose/issues/1377

Related

Docker Nginx with React and Laravel

So I want to have a single Nginx web server serving both frontend and backend with Docker.
Here is my docker-compose:
version: "3.8"
services:
db: #mysqldb
image: mysql:5.7
container_name: ${DB_SERVICE_NAME}
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
SERVICE_TAGS: dev
SERVICE_NAME: mysql
ports:
- $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
networks:
- backend
mrmfrontend:
build:
context: ./mrmfrontend
args:
- REACT_APP_API_BASE_URL=$CLIENT_API_BASE_URL
- REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
- REACT_APP_FRONTEND_ENDPOINT=$REACT_APP_FRONTEND_ENDPOINT
- REACT_APP_FRONTEND_ENDPOINT_ERROR=$REACT_APP_FRONTEND_ENDPOINT_ERROR
- REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
- REACT_APP_NAME=$REACT_APP_NAME
- REACT_APP_OWNER=""
ports:
- $REACT_LOCAL_PORT:$REACT_DOCKER_PORT
networks:
- frontend
nginx:
image: nginx:alpine
container_name: backend-nginx
restart: unless-stopped
ports:
- 8000:80
volumes:
- ./MRMBackend:/var/www
- ./docker-compose/nginx/backend:/etc/nginx/conf.d/
networks:
- backend
- frontend
app:
build:
args:
user: admin
uid: 1000
context: ./MRMBackend
dockerfile: Dockerfile
image: backend
container_name: backend-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./MRMBackend:/var/www
networks:
- backend
volumes:
db:
networks:
frontend:
driver: bridge
backend:
driver: bridge
And here's the Dockerfile for the frontend:
FROM node:16.13.0 as build-stage
WORKDIR /app
COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm i
ARG REACT_APP_API_BASE_URL
ARG REACT_APP_BACKEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT_ERROR
ARG REACT_APP_CUSTOMER
ARG REACT_APP_NAME
ENV REACT_APP_API_BASE_URL=$REACT_APP_API_BASE_URL
ENV REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT = $REACT_APP_FRONTEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT_ERROR = $REACT_APP_FRONTEND_ENDPOINT_ERROR
ENV REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
ENV REACT_APP_NAME=$REACT_APP_NAME
ENV GENERATE_SOURCEMAP=false
RUN npm run build
The problem is that the frontend container can't seem to start. It exit always at startup.
From my understanding I should copy the build content of the build-stage into the nginx folder "/usr/share/nginx/html" but how can I do it from the docker-compose file?
Just using volumes won't work. I need nginx in the docker-compose because it's also serving the backend.
Please note that the backend is working correctly.
UPDATE
My first approach was to use a Dockerfile for the frontend where I copied the content of the build directly into an Nginx image
# Stage 1
FROM node:16.13.0 as build-stage
WORKDIR /app
COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm i
ARG REACT_APP_API_BASE_URL
ARG REACT_APP_BACKEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT_ERROR
ARG REACT_APP_CUSTOMER
ARG REACT_APP_NAME
ENV REACT_APP_API_BASE_URL=$REACT_APP_API_BASE_URL
ENV REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT = $REACT_APP_FRONTEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT_ERROR = $REACT_APP_FRONTEND_ENDPOINT_ERROR
ENV REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
ENV REACT_APP_NAME=$REACT_APP_NAME
#avoid javascript out of memory
ENV GENERATE_SOURCEMAP=false
RUN npm run build
# Stage 2
FROM nginx:1.17.0-alpine
COPY --from=build-stage /app/build /usr/share/nginx/html
EXPOSE $REACT_DOCKER_PORT
CMD nginx -g 'daemon off;'
But in this way I think I'm deploying two Nginx. One in the Dockerfile and one in the Docker-compose. Am I right?
#federico-arona
As stated in my comment: If you want to have 1 nginx you need to share or copy the files from the container that is building the app.
Based on your requirements and what you wanted to accomplish. The best solution is named volumes, as they can be shared across containers.
They are the preferred mechanism for persisting data generated by and used by Docker containers. Plus you can manage volumes using Docker CLI commands and the Docker API. The Official docs show other benefits and additional information on how to use them.
I mostly use Docker multi-build to configure my FE app. Hope this might help you!
FROM node:16.13.0 as build-stage
WORKDIR /app
COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm install
RUN npm run dev
#Build Files
FROM nginx:1.19.10-alpine
COPY nginx-conf /etc/nginx/conf.d/default.conf
COPY --from=build /app /home/ubuntu/app/dist
you can use default nginx configuration.

Use enviroment variables in docker-compose.yml file in VueJS application

Please tell me how you can pass environment variables to the VUE application from the docker-compose.yml file. For some reason, after the yarn build command in .gitlab-ci.yml, the application sees only env variables that are written in the "env.production" file
My docker-compose.yml
version: "3.7"
services:
develop_dashboard_frontend:
image: some_image:latest
container_name: develop_dashboard_frontend
environment:
VUE_APP_API_URL: "some_api_URL"
ports:
- "127.0.0.1:8016:80"
restart: always
Any ideas?
You will need to put dashes (-) before each environment variable you want to specify, like you did it with ports in your example.
Refer to: https://docs.docker.com/compose/environment-variables/
$ cat docker-compose.yml
version: '3'
services:
api:
image: 'some_image:tag'
environment:
- VARIABLE_NAME=variable_value
You also need to distinguish between build time and runtime environment variables.
You can supply environment variables for your build, but that might not be saved for the runtime. It really depends on your build (I'm not familiar with yarn build).
However, I recommend using supplying the env variables for run time.
Just define them in the yaml as you tried.
Using $ docker stack deploy or docker-compose up it should work.

How to copy files from docker container to host using docker-compose in docker-machine

I have reports generated in gradle container for my selenium tests, I am trying to copy the files from docker container to local host. As a work around, I have used docker cp to copy files from container to my local and it works. How to achieve it with docker-compose volumes.
Below is my docker-compose.yml
version: "3 "
services:
selenium-hub:
image: selenium/hub
container_name: selenium-hub_compose
ports:
- "4444:4444"
chrome:
image: selenium/node-chrome-debug
container_name: selenium-chrome
depends_on:
- selenium-hub
ports:
- "5900"
environment:
- http_proxy=http://x.x.x.x:83
- https_proxy=http://x.x.x.x:83
- HUB_HOST=selenium-hub
- HUB_PORT=4444
gradle:
image: gradle:jdk8
container_name: selenium-gradle
build:
context: .
dockerfile: dockerfile
I run the command docker-compose up -> it runs the selenium tests and generates the report in the container.
Can anyone help on this?
The normal way to pass data from container to host is using docker volumes.
In short you specify a host directory and map it to the directory inside container. And that directory should be used to save your test reports
services:
selenium-hub:
image: selenium/hub
container_name: selenium-hub_compose
ports:
- "4444:4444"
volumes:
- ./path/to/report/folder:/host/reports
See docker documentation
https://docs.docker.com/compose/compose-file/#/volumes-volumedriver
Similar question:
How do I mount a host directory as a volume in docker compose
Power off the machine in Virtual box -> Change the Advanced settings in Virtual box
Goto Shared Folders in Virtual box
Give Path :: C:\DockerResults : Give a logical name for the Folder name
Restart the machine in DockerTerminal with the below command
docker-machine restart default
After machine is started open the Virtual box
Create a directory in the Virtual machine : sudo mkdir /Results
Mount the directory to the local windows machine by executing the below command in virtual box:
Sudo mount –t vboxsf DockerResults /Results
Add volumes as below in docker-compose file
volumes:
- /DockerResults:/home/Reports/

Module (nodemon) not found(package.json not found) DOCKER ISSUE

i'm trying to dockerize my express app, but when i try to run the CMD in the container , docker says me ' "Command \"nodemon\" not found."' like it doesn't find package.json in container. This is my dockerfile:
FROM node:8
WORKDIR /express-app/
COPY package.json .
RUN yarn
COPY . .
ARG MONGO_DB_DATABASE
ENV MONGO_DB_DATABASE ${MONGO_DB_DATABASE}
ARG MONGO_DB_USERNAME
ENV MONGO_DB_USERNAME ${MONGO_DB_USERNAME}
ARG MONGO_DB_PASSWORD
ENV MONGO_DB_PASSWORD ${MONGO_DB_PASSWORD}
EXPOSE 3000
CMD ["yarn", "start"]
and this is my docker-compose.yml
express-app:
build: ../../express-app
command:nodemon
environment:
- MONGO_DB_DATABASE=testDb
- MONGO_DB_USERNAME=test
- MONGO_DB_PASSWORD=test
expose:
- 3000
ports:
- "3000:3000"
volumes:
- ../../express-app:/express-app
depends_on:
- mongodb
links:
- mongodb
restart: always
Somewhere in your Dockerfile, throw in a RUN npm install nodemon -g. That installs and adds to your path

Unable to copy file from docker-compose mount to host

I am unable to copy a file generated by my Selenium tests in a folder inside docker container mounted to host machine.
Here is how my compose file look like
selenium:
image: 'selenium/standalone-chrome'
expose:
- "4444"
tests:
build:
context: ./tests
dockerfile: Dockerfile
depends_on:
- selenium
- web
volumes:
- /testResultsReport:/testResultsReport
This is how my directory structure looks like.
\
- docker-compose.yml
- build scripts
- tests
- testResultsReport
- Test scripts
Name of the file generated inside testResultsReport folder when running docker-compose is TestResultsReport.HTML
As my tests are running inside selenium server on port 4444, should I mount my volume there? I tried doing that to but still not getting my html file copied to host machine?
I confirmed that my html file is generated when i run my tests outside compose.
I also tried ./testResultsReport however it added a folder in root with name of testResultsReport and did nothing. So I used ./tests/testResultsReport but still not getting file.
Worked by using right folder and absolute path. Thanks #chrisz
selenium:
image: 'selenium/standalone-chrome'
expose:
- "4444"
tests:
build:
context: ./tests
dockerfile: Dockerfile
depends_on:
- selenium
- web
volumes:
- ./tests/testResultsReport:/tests/testResultsReport