DEV Community

Liem Le Hoang Duc
Liem Le Hoang Duc

Posted on

Docker basics

I'm here to share and well as to note some basics about Docker.
I'm Java developer, so I will mapping the concept from Java to Docker. If something confused you, please add comment and I will answer/update accordingly.

Terms

Docker Machine

The host/machine which is run docker server.
If you run Docker on Mac you will have a Virtual Machine which is, in this case, a Docker Machine

Image

Similar to Java, you packaged your app into Jar/War file and then your server will run it.
Similar to Docker, Image is a type of package that contains all of your things extras some OS files (/usr/bin, etc...).

Container

From Java point, you have Jar/War file, then you run it by java -jar your-jar.jar. The Java Runtime will starting to run your bytecode and you have a process.
Same for Docker, when you type docker run your-image, the docker runtime (currently default is runc) will start to run your image and create a process, which is, in docker terms - container.

Tag

Tagging or Versioning is always important.
When I was using Java, I just created my Jar/War and then Upload it to repository, say, version 1.0.0-RELEASE then the Ops guys will download that file from Repository and Run it.
In Docker, I have an image, I tag it, and then I push it into repository.
Tag is just the old wine in new bottle.

Volume

In Java, most of the time you will read/write file directly on Host Machine/Server and usually, that file will remain until you delete it.
In Docker, every time start a new container, the file system is fresh, none of your files from previous session will remain. This is a so-called "immutable". To solve that problem, Docker have a concept called volume.
To bind a volume inside Docker, simply add option --volume or -v for short.

Frequency used commands

docker run

Start a container

$ docker run --rm -it -P -v /tmp:/tmp/host ubuntu:18.04

In above command:
--rm mean: after this container finish execute, clean it!
it mean: Interactive shell. Without this, if your application require you to input, you cannot do it.
-P mean: If this container EXPOSE ports, please expose all of those ports randomly on DockerMachine. To bind specific port, 1323 for example. -p 11323:1323. Where 11323 is the port on Host Machine, and 1323 is port expose by container.
-v /tmp:/tmp/host mean: bind "/tmp" from host volume to "/tmp/host" in container.
Other useful options:
-d: Run container in detached mode. You shell will be freed immediately
--name: Name your container, then use can interact with its.

docker logs

$ docker run --name my-nginx --rm -p 38080:80 -d nginx:latest

Then curl 127.0.0.1:38080

Finally, to see access log of Nginx. docker logs my-nginx
Above command will print full logs of my-nginx container. To limit and follow limited line of logs, use docker logs --follow --tail 10 my-nginx

docker exec

$ docker exec -it my-nginx /bin/bash

This command is very useful to debug our code.
"Is my code created file as I expected?"
"How do I know if my code have all it dependencies? ldd my-binary!"
Using docker exec give you the same power as ssh to your server.

docker pull

$ docker pull containous/whoami

Will download containous/whoami:latest image to your machine.
To break down docker run, like we do in git.
git clone = git init + git remote add + git pull
docker run = docker pull + docker container create + docker container start

After testing and learning, now it's time to create our own docker image.

docker build

Here my file template for almost every project (Golang)

ARG BASE_IMAGE=gcr.io/distroless/base
FROM golang:1.14 as builder
COPY . /work
WORKDIR /work

RUN CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o app main.go


FROM $BASE_IMAGE
LABEL maintainer="contact@liemlhd.com"
# Copy Built App
COPY --from=builder --chown=65532:65532 /work/app /app/app
USER nonroot
WORKDIR /app

EXPOSE 1323

ENTRYPOINT ["./app"]

And then

$ # To build production image
$ docker build -t saboteurkid/go-demo:latest -f Dockerfile .
$ # To build test/dev image
$ docker build -t saboteurkid/go-demo:latest-debug \
 --build-arg BASE_IMAGE=saboteurkid/ubuntu:18.04-base \
 -f Dockerfile .

docker push

Finally, Push you Image to the Repository

$ docker push saboteurkid/go-demo:latest
$ docker push saboteurkid/go-demo:latest-debug 

Some others useful commands:

docker tag: this is useful when you want to rename a tag to difference name. Say I want to fork a saboteurkid/go-demo:1.0.0 version from saboteurkid/go-demo:latest. Simply type:

$ docker tag saboteurkid/go-demo:latest saboteurkid/go-demo:1.0.0

docker commit: this is useful when you want to commit your changes after add some changes to your container. Example:

$ docker exec my-nginx cp /etc/hosts /tmp/hosts
$ docker commit my-nginx saboteurkid/nginx-with-text-file
$ docker run --rm -it -d --name nginx-with-file saboteurkid/nginx-with-text-file
$ docker exec nginx-with-file cat /tmp/file.txt | head -n1 
$ # Will show: `127.0.0.1 localhost`

Top comments (0)