Creating a Dockerfile

1) Specify a base image

2) Run some commands to install additional programs

3) Specify a command to run on container startup

Eg, for running redis server, create a file named Dockerfile

#Use a base image
        FROM alpine

        #Manage dependencies (apk depends on alpine)
        RUN apk add --update redis

        #Startup command (note the space after CMD)
        CMD ["redis-server"]

Building Dockerfile

Build the image from the directory containing Dockerfile

docker build .
(or) docker build -f [Custom Dockerfile Name] . #if using another name for Dockerfile
# On successful build, you ll see the image id

Or, get the image id

docker images

Run the image

docker run [IMAGE_ID]

If you want to have a name for your image, use -t while docker build. The following naming convention is widely used for docker projects:

docker build -t [DOCKER_ID]/[IMAGE_NAME]:[VERSION_TAG] .
docker run senesence/redis #if the version tag is not mentioned, :latest will be used if available

Managing images

To remove a built image

docker rmi [IMAGE_NAME]

To rename a built image

docker tag [OLD_IMAGE_NAME] [NEW_IMAGE_NAME]
docker rmi [OLD_IMAGE_NAME]

To push images to docker hub

docker login --username=[USERNAME] #first time
docker push [DOCKER_ID]/[REPOSITORY_NAME]:[VERSION_TAG] 
#To push, image name should be in above format

To pull from docker hub

docker pull [DOCKER_ID]/[REPOSITORY_NAME]:[VERSION_TAG]

To save an image into a tar archieve

docker save [IMAGE_NAME] > [ARCHIEVE_NAME].tar

To load the image in different computer

docker load --input [ARCHIEVE_NAME].tar  #This will place a copy of that image locally
docker images

Generating image from container

Sometimes, we load an image in shell, make some changes to file system and generate a new image. To do this,

docker run -it alpine sh
/@: apt add --update redis

Open new terminal, and get the container id and commit (note the single and double quotes and space after CMD)

docker ps
docker commit -c 'CMD ["START COMMAND"]' [IMAGE_NAME]

This will create a new image of the container. However, it is always recommended to use the Dockerfile as we can recreate the build in different machine.

Copying files to container, setting work directory and mapping ports

In real projects, we ll have project files to be run on container. We want to copy those files to FS and change the working directory to the directory containing files

project dir:

main.py

from flask import Flask

            app = Flask(__name__)
            app.debug=True

            @app.route('/')
            def index():
                return "<h1>Hi</h1>"

            if __name__ == '__main__':
               app.run(host='0.0.0.0',port=8000)

requirements.txt

flask==1.0.2

Dockerfile

#In Docker, tag alpine referes to light weight versions (~100MB)
FROM python:3.7.1-alpine3.7
#Set working directory. If path does not exist, it is created
WORKDIR /home
#Copy files from current host directory to current working directory (/home)
COPY ./ ./
#Install flask
RUN pip install -r requirements.txt
#run script
CMD ["python","main.py"]

Build Dockerfile

docker build -t senesence/flask .

Note that flask runs on port 8000 in the container.

Host machine port need not be same as container port

The port mapping should be explicitly specified during docker run

docker run -p [HOST_PORT]:[CONTAINER_PORT] senesence/flask

For the above example, if we want to post the website on port 5000, for flask container on port 8000

docker run -p 5000:8000 senesence/flask

Open browser and hit

localhost:5000

NOTE: Editing files within container are not saved once container is exited! Copy is usually used for creating production images

Mount directories

Most often, we dont want to copy but have folders in sync between container and host machine

To do this, we use the -v option on docker run

Dockerfile (This time, We specify working dir on run time)

FROM python #(Full version ~ 900MB)
#Install vim and flask
RUN apt-get update
RUN apt-get -y install vim #-y is important to make installation not prompt for keyboard input
RUN pip install flask==1.0.2
#run script
CMD ["bash"]

Run -v [HOST_DIR]:[CONTAINER_DIR] -w [CONTAINER_WORK_DIR]

docker run -it -p 8080:8000 -v $PWD:/home -w /home senesence/flask:mount bash

Now changing anytyhing under /home in container will be reflected in the host machine (or vice versa)

IMPORTANT:

Directories are not copied but just referenced. Useful while developing and for big data

Creating new files from within container will set owner as root. Therefore, have atom running on host machine to edit, and just use container for execution.

For production code, we however need to copy the code into the container

Using -v without HOST_DIR

Suppose some dependencies (say /home/dep) were installed inside the /home dir of container while building. And we dont want them to be overriden in the container. In this case, we want to sync directories leaving out a particular dir in contaioner:

docker run -v /home/dep -v [HOST_DIR]:/home [IMAGE_NAME] bash