Docker Cheatsheet
Tags: docker
Published: 2021-03-10 17:06:55

`docker run -dit ubuntu` to create and run a docker ubuntu instance that you can enter.
`docker ps` to find your running containers
`docker ps -all` to show all of your containers
`docker ps -a` to show your docker container history
`docker exec -it containerId bash` or `docker exec -it containerId sh` will enter the docker linux container that you have created.
`docker create` takes an instance of an image and creates a unix container with that image.
`docker run = docker create + docker start` - creates and starts a container (it pulls the image if necessary)
`docker compose up` and `docker compose down` starts up. shuts down containers as defined in a `docker-compose.yml` file.
`docker compose up --build` builds the image and then runs docker compose up
`docker compose up -- build > log.txt` does the same but exports any STDOUT to log.txt
`docker compose up --detach` starts the containers in the background and leaves them running.

A very basic `docker-compose.yml` file pointing to a `Dockerfile` in the root:

`
version: "3.9"
services:
  myservicename:
    build: .
    ports:
      - "81:8000"
` 

Basic Dockfile
`
FROM node:16-alpine
WORKDIR /app
COPY ./package.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
`
you could run this dockerfile like `docker build -f./Dockerfile . -t stuartcreedweb` then `docker run -p 3000:3000 -d stuartcreedweb --name=stuartcreedweb`

This could run a standard local node version for a simple web app

To run a node container without any commands or files create a Dockerfile with:
```
FROM node:16-alpine
WORKDIR /app
```
Then run `docker build . --tag=testnode` and then `docker run docker run -dit --name=testnodecontainername testnode`. Note that the -it flag is required to keep the container running as well as -d flag.

To create a detached container create a docker-composer file with the tty option (not required if you execute a long running process), e.g. :
```
version: "3.9"
services:
  node: 
    build: .
    ports:
    - "81:8000"
    tty: true
```
Volumes are required to persist files. This can be done in the Dockerfile, on the run command or in docker compose. To define a volume in docker you can define it like:
```
FROM node:16-alpine
WORKDIR /app
VOLUME /app
```
This creates an anonymous volume which persists the file if you stop and then start the volume again. To do a similar thing with the docker run command.

`docker run --rm -dit -p=3000:3000 --name=nameofcontainer -v $(pwd):/app imagetag`

**In regards to what EXPOSE is in Dockerfile:**

Basically, you have three (four) options:

1) Neither specify EXPOSE nor -p
2) Only specify EXPOSE
3) Specify EXPOSE and -p
4) Only specify -p which implicitly does EXPOSE
1) If you specify neither EXPOSE nor -p, the service in the container will only be accessible from inside the container itself.
2) If you EXPOSE a port, the service in the container is not accessible from outside Docker, but from inside other Docker containers. So this is good for inter-container communication.
3) If you EXPOSE and -p a port, the service in the container is accessible from anywhere, even outside Docker.
4) If you do -p, but do not EXPOSE, Docker does an implicit EXPOSE. This is because if a port is open to the public, it is automatically also open to other Docker containers. Hence -p includes EXPOSE. This is effectively same as 3).

But the easiest way to set up a docker volume is in a docker compose file e.g: 
An example more complicated dockerfile with multiple services:
```
version: '3.9'
services:
  remixnode:
    build: 
      context: ./remix
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    volumes:
      - "/app/node_modules"
      - "./remix:/app"
  mssql:
    image: 'mcr.microsoft.com/mssql/server:2022-latest'
    environment:
      - ACCEPT_EULA=Y
      - MSSQL_SA_PASSWORD=NodePrismaApp2022!
    ports:
      - "1437:1433"
```
Dockerfile in '/remix':
```
FROM node:18-alpine
WORKDIR '/app'
COPY './package.json' './'
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
```
In the docker-compose file the - "/app/node_modules" volume tells docker to not try to sync your local nodemodules with the one created in the docker container and map it to a seperate volume instead. es-build is fussy with the environment in which you run an npm install with it - mac, linux, windows etc so it is best to run npm install in the container. It also caches the node modules folder so you do not have to run npm install every time unless there is a change.

To get the ip address of a docker container locally: ```docker inspect <container_name_or_id> -f  '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'```