Docker Images Working— Core Concept
Docker Image:
- An image is ‘read only’ template for creating containers.
- Image is made by bunch of independent layers that are stacked on top of each other, loosely connected by a manifest JSON/YAML file.
- Images are ‘Build-Time Construct’ and containers are their runtime siblings. [i.e. containers = running image]
- A single image can be shared by multiple containers.
- Images are stored in a registry. Registry can be cloud or on-prem.
Q. If images are read only how container write stuff ?
- For each container, we create a thin writable layer.
- Any writes and updates needed for containers are performed here.
Docker Image Architecture:
- It follows a layered architecture.
- Each line of instruction in Docker file creates a new layer in docker image with just the changes form the previous layer.
- Example:
FROM … (base image)
RUN …
COPY …
WORKDIR …
RUN …
EXPOSE …
ENTRYPOINT ..
Working with Docker Images:
$ docker pull <image-name>
- Image lives in registry. While pulling image, if registry name is not mentioned, Docker-hub will act as a default registry
- If the image tag is not specified, ‘latest’ image is pulled.
- By default docker images are stored in following directory:
Linux :- /var/lib/docker/aufs
Windows :- C:\\program data\docker\windows filter
Introduction to Dockerfile:
Dockerfile is a list of instructions for building images.
Example:
FROM alpine
LABEL maintainer = “abc@mail.com”
COPY ./src
WORKDIR /src
RUN npm install
EXPOSE 8080
ENTRYPOINT [“node”, “./app.js” ]
- Capitalize instructions. [i.e. <INSTRUCTIONS> <value>]
- FROM — is always first instruction which defines the base image on which the app runs.
- LABEL — It is good practice to list maintainer.
- RUN — executes command and creates a new layer.
- COPY — copy code into image as new layer
- WORKDIR/EXPOSE/ENTRYPOINT — these are used as instructions and metadata instead of layers.
- ENTRYPOINT — default app for image/container
Building Image:
1. Basic Image build:
$ docker build -t <image_name> <path_to_dockerfile_context>
$ docker build -t myapp_image .2. Building an Image with Specific Tag:
$ docker build -t <image_name>:<tag> <path_to_dockerfile_context>
$ docker build -t myapp_image:1.0 .3. Building from a Specific Dockerfile:
$ docker build -t <image_name> -f <path_to_dockerfile> <path_to_dockerfile_context>
$ docker build -t myapp_image -f docker/Dockerfile.prod .4. Building an Image with Build Arguments:
$ docker build -t <image_name> — build-arg <key>=<value> <path_to_dockerfile_context>
$ docker build -t myapp_image — build-arg ENVIRONMENT=production .5. Building an Image with No Cache (force a fresh build):
$ docker build -t <image_name> — no-cache <path_to_dockerfile_context>
$ docker build -t <image_name> <git_repository_url>6. Building an Image from a Git Repository:
$ docker build -t <image_name> <git_repository_url>
$ docker build -t myapp_image https://github.com/username/myapp.git7. Building an Image with a Build Context from a Remote URL:
$ docker build -t <image_name> — remote <git_repository_url>
$ docker build -t myapp_image — remote https://github.com/username/myapp.git
Multi-Stage Build:
- We aim for small images with minimal OS and packages.
- Sometimes maybe, we need too much packages an OS layer to add while creating image which results to ‘Bloated Image’ with unnecessary packages.
- Thus, ‘Multi-Stage Build’ comes to the rescue.
- Example:
Storing Images:
1. Push to Docker Hub (Remote Repository):
$ docker login
$ docker tag <local_image_name>:<tag> <dockerhub_username>/<repository_name>:<tag>
docker push <dockerhub_username>/<repository_name>:<tag>
$ docker tag myapp_image:1.0 myusername/myapp_image:1.0
$ docker push myusername/myapp_image:1.02. Push to Other Remote Registry (e.g., AWS ECR, Google Container Registry, etc.):
$ docker login <registry_url>
$ docker tag <local_image_name>:<tag> <registry_url>/<repository_name>:<tag>
$ docker push <registry_url>/<repository_name>:<tag>3. Export and Import Image (Local Repository):
$ docker export <container_id> > <output_filename>.tar
$ cat <input_filename>.tar | docker import — <local_image_name>:<tag>