Docker Fundamentals
docker version
will show you the version that is installed in your system. It will show the version for both client and server, the server version will be shown only if the docker is running on the your machine.
Development workflow
To dockerise a application we just have to add a Dockerfile in it. A Dockerfile
is a set of instructions that docker uses to
package this application into an image. This image contains everything that our package need in order to run. i.e
- A Cut Down OS.
- A runtime environment (eg Node)
- Application Files
- Third party libraries.
- Environment Variables etc.
One we have an image we tell docker to start the container using that image. A container is just an process which has it's own filesystem provided by the image, so our application is loaded inside our container. This is how we run our application in our machine.
This image can be pushed to the docker hub just like we push our code to the git. Once the application is in the dockerhub we can pull it in any machine i.e on production or test.
Two Most Important Things (Images and Container)
Images are the blue print for container, It's actually the images the contains everything that is required to run the code. Image is a sharable package with all the setup instruction and the container is a running instance of such image.
(Pre built or Existing Image on Docker Hub)
docker run node
docker run -it node // run docker on interative mode.
(Build you own Image: NODE JS Example)
FROM node
WORKDIR /app
#Copying the package.json file first because we don't want to run npm install command even when the internal code changes.
COPY package.json /app
RUN npm install
COPY . /app
# Since the docker environment in isolated and has it's own internal network. Therefore the internal port has to be exposed to our local system.
EXPOSE 80
# RUN node server.js # Incorrect because we don't want to run th server in a image we want to do that in container. We only want to start a server if you starta container based on that image. Therefore use CMD insteand of RUN.
CMD ["node", "server.js"]
Now run the docker build .
or docker build -t my-image-name:tag .
in the folder where your Dockerfile is. This will build your image.
my-image-name
is the repository name.tag
is optional (defaults to latest if not provided).
docker image prune
if you flush images.
Finally you can run the docker run -p 3000:80 image_name
. Here you also specify the port 3000
which will mapped to the docker exposed port 80
.
Stop the container with docker stop container_name
NOTE: However This image build will not build the code everytime you change your code. You will have to docker build . to rebuild this image and docker run -p 3000:80 new_image
COPY . /app meaning copy everything from root folder (local machine where we have to Dockerfile) to docker image app directory (which we set as our project's directory).
Every container has it's own internal filesystem which is totally detached from your local file system and is hidden away inside the docker container. The /app
folder will be created if it does not exists.
WORKDIR /app All the commands should be executed in the /app folder inside the container.
Managing Images & Container
docker ps
to list the running containerdocker ps -a
to list also the stopped container.docker start [image_name]
to restart the container because there is no need to create new container everytime if nothing has changed.docker run -p 8000:80 -d [image_name]
to start the container in detach mode. Detach mode does not keep listening in the terminal even if the application is running. The defauld mode isattach
when running the run command.docker attach [image_name]
to attach yourself in the running container.docker logs [image_name]
to view theconsole.log
in detached mode. Alsodocker logs -f [image_name]
show log and keep on listening -f is follow.docker run -it image_name
to run the image in interactive mode i.e you can also input the data if the app is listening for your input via terminal.docker rm container_name1 container_name2 contaier_name3
to remove the container. You will have to stop the container first.docker images
to list the images that were built.docker rmi image_nme
to remove images. You must delete the container before you delete the image or you can do--force
docker image prune
to remove all the unused images.- Add
--rm
in the run command to rm the docker automatically when it stops.docker run -p 3000:80 -d --rm image_name
.docker stop
will also delete the container. docker image inspect image_id
to view addditional information about the image.docker cp
Add folder/file to a running container withdocker copy dummy/. container_name:/path_where_to_copy
you can also copy folder/file from docker to your systemdocker cp container_name:/path/file local_folder
this will help- Docker Name with
--name
. Build image with detach mode and rm on stop and with a namedocker run -p 3000:80 -d --rm --name selvesan image_name
- A image name has two part name and tag
name:tag
eg:node:14
. Build a image with name and a tagdocker build -t selvesan:latest .
. The tag name can be nuber or string. Now you can run the image with the namedocker run -p 3000:80 -d -rm --name contaier_name selvesan:latest
docker image prune -a
to delete all the images.
Sharing Images
- Create account in docker hub
- Create a repository
- The newly create repository will give you a command to push into that repository.
docker push selvesan/node-app
- The docker image's name should be the repositories name
docker tag old_name selvesan/node-app
. Here we are renaming the already available image. docker login
to login from the terminal- Finally
docker push selvesan/node-app
docker pull selvesan/node-app
to pull the docker image. Run the same pull command to update the docker image.
Managing Data/Volumes in Images and Container
Three kinds of data are
- Application (Code / Environment) which is added to the container when the container is built and is Fixed cannot be changed once the container is built. This can be readonly because it is stored in image.
- Temporary Data (User input value stored in a variable) stored in memory or temporary files which is dynamic and changing but cleared regularly. This can be read / write because it is stored in container.
- Data that need to be persist data should be there even if the container stops. (Database stored data). Can be read/write and stored in container and volumes.
Volumes are the folder on your host machine (Your Computer) which are mounted into containers. With volume you can map folder outside on a container to inside of a container so adding file to this folder container can access it and file added by the container we can access it. Because of this container allows us to persist data. Note: The volume must be named in order for it to survive because named volumn are not attached to container therefore it wonn't get deleted when the container stops.
To create a named volumn
docker run -d -p 3000:80 --rm --name feedback-app -v feedback_storage:/app/feedback image_name
Here -v volumn_name:/volume/path
is defining a volumn in a path inside container.
Bind Mountes
The subsequent changes in the code would reflect in the image unless we manually build the image again. We always have to build the image and restart the container everytime we make the change. Here's where the bind mount will help us. Bind mounte are perfect for persistance and editable data.
docker run -d --rm -p 3000:80 --name feedback-app -v feedback:/app/feedback -v "/Users/path/to/your/app:/app" -v /app/node_modules image_name
- the first volume
-v feedback:/app/feedback
a volume namedfeedback
which is mounted inside a container directory /app/feedback - the second volume
-v "/Users/path/to/your/app:/app"
is to make the docker internal volume mounted to our local folder to reflect the changes as we make changes to the code - the third volume
-v /app/node_modules
is a anonymous volume created just to ignore the replacement ofnode_modules
when the localstorage is mounted in docker's/app
directory
Overview
- Anonymos volumes is created for a container and is removed when the container is stoped.
- Named volumes cannot be created in the Dockerfile should be created with the
-v
flag when running the container. Is not tied to a container - In Bind Mounts we know where the data is stored in host machine
Read Only Volumes
First of all the idea of bind mounte is to ensure that the changes made in local file system is feflected on the container. For eg: The changes done on our codes is automatically available inside of the container.
However we should not allow the container (or the running application inside the container) to make changes in the host machine that is our local device only we should be able to do so. This is why we might want
to enfore this bind mount into a read only volume. By default volumes are read / write, but you can restrict this by adding a extra column and ro
for readonly.
docker run -d --rm -p 3000:80 --name feedback-app -v feedback:/app/feedback -v "/Users/path/to/your/app:/app:ro" -v /app/node_modules image_name
Now there is a slight problem we made the entire project read only. However there might be cases where we want some of the directory to left of as read and write both for eg: file uploading directory
or some temp directory.
In order to understand how this can be achieved we need to understand a concept of override. eg: Here in the above docker run statement.
If we specify another sub volume inside of this entire project folder volume then that sub volume overrides that main volume. Now you should notice in the above docker run command the feedback volume is already writable
as it is a extra volume created inside containers subfolder /app
main folder and /app/feedback
sub folder.
If you want to add another writable folder -v /app/temp