How does the command key in docker-compose file work - docker

I am trying to understand the docker sample application 'example-voting-app'. I am trying to build the app with docker-compose. I am confused with the behaviour of 'command' key in docker compose file and the CMD Instruction in Dockerfile. The application consists of a service called 'vote'. The configuration for the vote service in docker-compose.yml file is:
services: # we list all our application services under this 'services' section.
vote:
build: ./vote # specifies docker to build the
command: python app.py
volumes:
- ./vote:/app
ports:
- "5000:80"
networks:
- front-tier
- back-tier
The configuration of the Dockerfile provided in ./vote directory is as below:
# Using official python runtime base image
FROM python:2.7-alpine
# Set the application directory
WORKDIR /app
# Install our requirements.txt
ADD requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt
# Copy our code from the current folder to /app inside the container
ADD . /app
# Make port 80 available for links and/or publish
EXPOSE 80
# Define our command to be run when launching the container
CMD ["gunicorn", "app:app", "-b", "0.0.0.0:80", "--log-file", "-", "--access-logfile", "-", "--workers", "4", "--keep-alive", "0"]
My doubt here is which command ( 'python app.py' or 'gunicorn app:app -b ...') will be executed when i try building the application using docker-compose up

The Docker Compose command:, or everything in a docker run invocation after the image name, overrides the Dockerfile CMD.
If the image also has an ENTRYPOINT, the command you provide here is passed as arguments to the entrypoint in the same way the Dockerfile CMD does.
For a typical Compose setup you shouldn't need to specify a command:. In a Python/Flask context, the most obvious place it's useful is if you're also using a queueing system like Celery with the same shared code base: you can use command: to run a Celery worker off of the image you build, instead of a Flask application.

Related

How to include Docker environment arguments when running docker compose?

I am new to Docker / docker compose and am using it to deploy an API to a server. I found an image that I wish to use, which includes the option to add some environment variables, in particular:
GUNICORN_CMD_ARGS
Any additional command line settings for Gunicorn can be passed in the
GUNICORN_CMD_ARGS environment variable.
Read more about it in the Gunicorn docs: Settings.
These settings will have precedence over the other environment
variables and any Gunicorn config file.
For example, if you have a custom TLS/SSL certificate that you want to
use, you could copy them to the Docker image or mount them in the
container, and set --keyfile and --certfile to the location of the
files, for example:
docker run -d -p 80:8080 -e GUNICORN_CMD_ARGS="--keyfile=/secrets/key.pem --certfile=/secrets/cert.pem" -e PORT=443 myimage
I would like to add these two options (keyfile and certfile) as arguments to the docker run command, but instead pass docker compose up to create the images and run the container.
How would I go about doing that?
My Docker file is:
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app /app
And my docker-compose.yml file is:
version: "3"
services:
backend:
build: ./
restart: always
network_mode: "host"
I have tried adding a CMD line to the end of my Docker file but to no avail.
You can use the environment key in you docker-compose.yml like this:
environment:
GUNICORN_CMD_ARGS: --keyfile=/secrets/key.pem --certfile=...
PORT: 443
https://docs.docker.com/compose/compose-file/compose-file-v3/#environment

How to copy a subproject to the container in a multi container Docker app with Docker Compose?

I want to build a multi container docker app with docker compose. My project structure looks like this:
docker-compose.yml
...
webapp/
...
Dockerfile
api/
...
Dockerfile
Currently, I am just trying to build and run the webapp via docker compose up with the correct build context. When building the webapp container directly via docker build, everything runs smoothly.
However, with my current specifications in the docker-compose.yml the line COPY . /webapp/ in webapp/Dockerfile (see below) copies the whole parent project to the container, i.e. the directory which contains the docker-compose.yml, and not just the webapp/ sub directory.
For some reason the line COPY requirements.txt /webapp/ works as expected.
What is the correct way of specifying the build context in docker compose? Why is the . in the Dockerfile interpretet as relative to the docker-compose.yml, while the requirements.txt is relative to the Dockerfile as expected? What am I missing?
Here are the contents of the docker-compose.yml:
version: "3.8"
services:
frontend:
container_name: "pc-frontend"
volumes:
- .:/webapp
env_file:
- ./webapp/.env
build:
context: ./webapp
ports:
- 5000:5000
and webapp/Dockerfile:
FROM python:3.9-slim
# set environment variables
ENV PYTHONWRITEBYTECODE 1
ENV PYTHONBUFFERED 1
# set working directory
WORKDIR /webapp
# copy dependencies
COPY requirements.txt /webapp/
# install dependencies
RUN pip install -r requirements.txt
# copy project
COPY . /webapp/ # does not work as intended
# add entrypoint to app
# ENTRYPOINT ["start-gunicorn.sh"]
CMD [ "ls", "-la" ] # for debugging
# expose port
EXPOSE 5000
The COPY directive is (probably) working the way you expect. But, you have volumes: that are overwriting the image content with something else. Delete the volumes: block.
The image build sequence is working exactly the way you expect. build: { context: ./webapp } uses the webapp subdirectory as the build context and sends it to the Docker daemon. When the Dockerfile for example COPY requirements.txt . it comes out of this directory. If you, for example, docker-compose run frontend pip freeze, you should see the installed Python packages.
After the image is built, Compose starts a container, and at that point volumes: take effect. When you say volumes: ['.:/webapp'], here the . before the colon refers to the directory containing the docker-compose.yml file (and not the webapp subdirectory), and then it hides everything in the /webapp directory in the container. So you're replacing the image's /webapp (which had been built from the webapp subdirectory) with the current directory on the host (one directory higher).
You should usually be able to successfully combine an ordinary host-based development environment and a Docker deployment setup. Use a non-Docker Python virtual environment to build the application and run its unit tests, then use docker-compose up --build to run integration tests and the complete application. With a setup like this, you don't need to deal with the inconveniences of the Python runtime being "somewhere else" as you're developing, and you can safely remove the volumes: block.

Container exited with code 0, and my app is served from the host OS

I want to dockerize a Next.js project.
I am using Ubuntu 20.04
I first created a Next.js app in my /home/user/project/ folder using npx create-next-app
So I have the project source code in my host machine.
But I want to dockerize it, so I created a docker-compose.yaml:
next:
build:
context: ./next
dockerfile: Dockerfile
container_name: next
volumes:
- ./next:/var/www/html
ports:
- "3000:3000"
networks:
- nginx
And this is the Dockerfile:
#Creates a layer from node:alpine image.
FROM node:alpine
#Creates directories
RUN mkdir -p /usr/src/app
#Sets an environment variable
ENV PORT 3000
#Sets the working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD commands
WORKDIR /usr/src/app
#Copy new files or directories into the filesystem of the container
COPY package.json /usr/src/app
COPY package-lock.json /usr/src/app
#Execute commands in a new layer on top of the current image and commit the results
RUN npm install
##Copy new files or directories into the filesystem of the container
COPY . /usr/src/app
#Execute commands in a new layer on top of the current image and commit the results
RUN npm run build
#Informs container runtime that the container listens on the specified network ports at runtime
EXPOSE 3000
#Allows you to configure a container that will run as an executable
ENTRYPOINT ["npm", "run"]
Then I build my container using docker-compose build && docker-compose up.
The container is built, but it's not running and is displaying EXITED (0)
and the LOGS has the following message:
Lifecycle scripts included in next-frontend#0.1.0:
start
next start
available via `npm run-script`:
dev
next dev
build
next build
lint
next lint
But of course if I run in the host npm run dev it will run the app from the host, and not from the container (It runs, but that's not what I want)
I feel like there is some very fundamental mistake in my deployment, but I just started with Docker so I can't find out what
Also, I copied the Dockerfile from a tutorial so it might not fit the way I created the project
ENTRYPOINT ["npm", "run"]... What?
From npm run documentation,
This runs an arbitrary command from a package's "scripts" object. If no "command" is provided, it will list the available scripts.
In the docker-compose.yml, you need to override the CMD instruction (that is empty in your case) with the npm script you want to run. Something like this:
next:
build:
context: ./next
dockerfile: Dockerfile
container_name: next
command: ["start"]
volumes:
- ./next:/var/www/html
ports:
- "3000:3000"
networks:
- nginx
Since you are using the Compose Spec, this is the reference for the command instruction.

How to make a docker compose file for an existing image?

What I am trying to do is use a Docker image I found online timwiconsulting/ionic-v1.3, and run my ionic project within Docker. I want to mount my ionic project in Docker and forward my ports so I can run the emulator in a browser.
I want to ask how do I create a docker-compose.yml file for an existing container?
I found a Docker image timwiconsulting/ionic-v1.3 that I want to run, which has the correct version of the tools that I want.
Now I want to create a compose file to forward the ports to my computer, and mount the project files. I create this docker-compose.yml file:
version: '3'
services:
web:
build: .
ports:
- "8100:8100"
- "35729:35729"
volumes:
- /Users/leetcat/project/:/project
But every time I try to do docker-compose up I get the error:
~/user: docker-compose up
Building web
Step 1/6 : FROM timwiconsulting:ionic-v1.3
ERROR: Service 'web' failed to build: pull access denied for timwiconsulting, repository does not exist or may require 'docker login
I am doing something wrong. I think I want to be creating a docker-compose.yml file for the container timwiconsulting/ionic-v1.3. Feel free to tell me I am totally off the mark with what docker is.
Here is my Dockerfile:
# Use an official Python runtime as a parent image
FROM timwiconsulting:ionic-v1.3
# Set the working directory to /app
WORKDIR /project
# Copy the current directory contents into the container at /app
ADD . /project
# Install any needed packages specified in requirements.txt
# RUN pip install --trusted-host pypi.python.org -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 8100
EXPOSE 35729
# Define environment variable
ENV NAME World
# Run app.py when the container launches
# CMD ["python", "app.py"]
# docker exec -it <container_hash> /bin/bash/

create docker-compose file from Dockerfile

I have this simple Dockerfile:
FROM node:boron
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install
# Bundle app source
COPY . /usr/src/app
EXPOSE 8080
CMD [ "npm", "start" ]
I would like to use docker-compose so that I can simply say docker-compose up or docker-compose down.
I am struggling to find a simple docker-compose example of how I would use docker-compose, all I can find are examples like this which cover more ground than I need.
How could I create a simple docker-compose file from the above?
You write following in docker-compose.yml file to run your docker container using compose:
version: '3'
services:
app:
build: .
ports:
- 8080:8080
Docker compose file is made of multiple services but in your case it is enough to define one service. build option specifies from where to pick up the Dockerfile to build the image and ports will allow port forwarding from the container to you host OS.
To start the service you can use:
docker-compose up
And to stop the service:
docker-compose down
You can find more documentation about the compose file here

Resources