Just looking to get running? Start here and adjust to fit your needs:
https://www.youtube.com/watch?v=gEceSAJI_3s
docker-compose.yml from the above
https://gist.github.com/erikyuzwa/7411752ddcb95b09434aa88f38d91630
Reference:
Structurally, a container behaves almost like a VM. Ultimately, it is just a process that runs on top of the OS, and can be started and stopped just like other processes.
Containers use the Linux kernel on windows (which ships with a linux kernel), and linux. On Mac, there’s an intermediary vm-ish program used, but the concept is the same.
Images are what results from running the build command on a given Dockerfile, which gives it an OS and initial setup instructions to put together the finished package. It’s an oversimplification, but think of the images as programs (though they aren’t) that are complied (also not correct) based on the instructions in the Dockerfile. Once those images are built, they can be run in containers.
On their own, containers don’t really contain anything other than images because they use the OS of the machine they’re running on. Further, they don’t require the dedicated resources of a VM, since they are technically just another piece of software running on the parent instead of taking their own dedicated resources from the hardware.
A container may contain multiple images, and containers use the filesystem of their images.
It might help to think of images as savegames and containers as games that are actually being played that originated as savegames
To dockerize an app:
Create a file named ‘Dockerfile’ in the root directory
FROM node:14.16.0-alpine3.13
RUN addgroup app && adduser -S -G app app
USER app
WORKDIR /app
RUN mkdir data
COPY package*.json .
RUN npm install
COPY . .
# ENV ENVIRONMENT_VARIABLE=x
EXPOSE 3000
CMD ["npm", "start"]
FROM specifies the parent image operating environment (which might be an OS, or an environment like node that runs on top of an OS, bundled as a single choice. See https://hub.docker.com/search?q=node ). In this case, the operating environment is node 14.16.0 running on alpine linux 3.13
RUN is part of building the image. Happens before CMD. In the above example, the first time this is used is to create a directory for our data to be stored that we can map to a directory on our local machine. In the second, a group ‘app’ is created and a user named ‘app’ is created and assigned to that group. This is done so that the application does not run as root, which is a security concern
USER runs all subsequent commands as if they were coming from the specified user
WORKDIR specifies the working directory of your application relative to the root directory. It’s roughly like using cd to move to your public_html or similar
COPY moves items from the current directory into the docker image. COPY . . is also correct, but in this case we want to avoid re-copying all of the node code every time we rebuild the image so we don’t do it until afterwards
CMD is the equivalent of running the listed bash commands at launch. In this case, we’re assuming we need node to be running in our image for the application to function, CMD handles that for us on startup. Takes an ‘array instead of spaces’ format to avoid spinning up an unneeded extra shell
EXPOSE exposes a port to the image. Note that this exposes the container to the port, but doesn’t affect the host. Mapping a container port to a host port is handled via the run command
Then build your image from the Dockerfile
docker build -t my-docker-image-name .
The period at the end specifies the current directory’s Dockerfile
Start a container with your image
To start a container with a specified image in interactive mode
docker run -it my-docker-image-name sh
To start a container with a specified image, leaving it to run in the background, mapping port 80 of the host to port 3000 of the container, giving it a name of ‘my-container-name’
docker run -d -p 80:3000 my-container-name my-docker-image-name
To start a container with a specified image, leaving it to run in the background, while assigning it the name ‘hungry-boy’ (container will be given an autogenerated name unless –name is specified)
docker run -d --name hungry-boy my-docker-image-name
To display all running containers
docker ps
To display all of the containers (including stopped)
docker ps -a
To remove all stopped containers
docker container prune
To restart a stopped container
docker start my-container-name
To stop a container
docker stop [container id]
To delete a stopped container
docker rm [container id]
To create a volume
docker volume create my-app-data
To view a volume’s contents
docker volume inspect my-app-data
To attach a volume to an image
To start a container with a specified image, leaving it to run in the background, mapping port 4000 of the host to port 3000 of the container, and attaching it to a volume so we can have data persistence
docker run -d -p 4000:3000 -v volume-name:/path/in/container/ image-name
To start a container with a specified image, leaving it to run in the background, mapping port 4000 of the host to port 3000 of the container, and binding a local directory (current working directory, in this case) to a directory inside our container. This will enable us to move things back and forth without having to rebuild after every change
docker run -d -p 4000:3000 -v $(pwd):/path/in/container/ image-name
To list available volumes
docker volume ls
To remove a volume
docker volume rm [volume-id]
To move data from container to local
docker cp container-id:/app/myfile.txt .
Like the cp command under normal circumstances, docker cp can also be used to move data from local to container using the same syntax
docker cp somefile.txt container-id:/app/
To retrieve an existing image from the docker repo
docker pull some-docker-image
Clear out dangling images
First, we can check to see available images on our machine:
docker image ls
or
docker images
If we see unused images, particularly images labeled, <none>, they are leftover remnants from old builds. We can clean out these leftover ‘dangling images’
docker image prune
To remove an image
docker image rm image-name-or-id
To save an image for export
docker image save -o output-file-name.zip name-of-image:tag
To load an image from an export
docker image load -i output-file-name.zip
To push a local image to dockerhub
First, create a repo on hub.docker.com. For the following cases, assume a repo named “sos611/testy-testerson”
Then, assign a tag to the local image. In the below case, the tag is “2”, but the “testy-testerson” portion is also assigned as part of the name itself. Think of the entire name testy-testerson:2 as a tag unto itself with a required colon followed by a version name/number
docker image tag [image id] testy-testerson:2
Then, make sure you’re logged in to docker hub:
docker login
Then push the repo to docker hub
docker push sos611/testy-testerson:2
To run a command on an already-launched container
docker exec container-nickname ls
To launch a shell session on an already-launched container
docker exec -it container-nickname sh
To launch a shell session on an already-launched container as root
docker exec -it -u root container-nickname sh
To stop a container
docker stop container-nickname
To build the docker services according to docker-compose.yml
docker compose build
Example docker-compose.yml:
services:
web:
build: ./frontent #location of the cockerfile
ports:
- 3000:3000
api:
build: ./backend #location of the Dockerfile
ports:
- 3001:3001
environment:
DB_URL: mongodb://db/vidly
db:
image: mongo:4.0-xenial
ports:
- 27017:27017
volumes:
- vidly:/data/db
volumes:
vidly:
Note that docker compose and docker-compose are equivalent
To run the built docker services in detached mode
docker compose up -d
To compose with a specified dockerfile
docker compose docker-compose-file.prod.yml up --build
To stop and delete running containers
docker compose down
To view the logs for a given container
docker logs [container id]
or, to view the logs live:
docker logs -f [conatiner id]
To view the networks created by docker compose
docker network ls