docker
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| docker [February 12, 2026 at 16:01] – yanevskiv | docker [June 13, 2026 at 03:13] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | # docker | ||
| + | |||
| + | ## What is docker? | ||
| + | **Docker** is a tool for managing containers. Containers are somewhat like virtual machine instances except a lot more lightweight. | ||
| + | |||
| + | Think of an application e.g. a web app. You want to run the application, | ||
| + | |||
| + | What does it take to run an application in a virtual machine? First, you first need to set up a virtual machine. This means giving it a slice of your hardware (CPU, RAM, HDD, ...). Then, you need to install an OS on the virtual machine (let's say, Ubuntu). Then, you also need to install everything the application needs (`apt install ...`). Finally, you need to copy your application inside the virtual machine. This works, but wastes a lot of resources + the application will obviously be a lot slower than it would have been if it was ran on the host. | ||
| + | |||
| + | What if instead of emulating hardware, we just run the application we wanted on the host, but somehow made the application " | ||
| + | |||
| + | But actually, it's even better! Not only can we make an application " | ||
| + | |||
| + | Therefore, it's actually more appropriate to think of Docker as an " | ||
| + | |||
| + | ## Install | ||
| + | Follow the guide on https:// | ||
| + | |||
| + | On Debian and Ubuntu systems, this usually boils down to modifying `/ | ||
| + | ```bash | ||
| + | $ sudo apt update | ||
| + | $ sudo apt install | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | ``` | ||
| + | |||
| + | If you want to make a regular user be able to use `docker` command, just add them to the `docker` group: | ||
| + | ``` | ||
| + | $ sudo gpasswd -a john docker | ||
| + | $ sudo groups john | ||
| + | john : john docker | ||
| + | ``` | ||
| + | Remember that they will have to log out and then log back in, in order for their groups to update. | ||
| + | |||
| + | ## Practice | ||
| + | In order to see what Docker is in practice, it's best if you try it yourself: | ||
| + | ``` | ||
| + | docker run -it --rm ubuntu: | ||
| + | ``` | ||
| + | This puts you inside a container, running bash shell as root. You can now use `apt` to install anything you like. You can also break the system if you like (e.g. run `rm -rf /usr`). When you exit the shell, everything you ever did inside is lost. This includes anything you installed, but also anything you created, edited, changed, removed, or broke. | ||
| + | |||
| + | When you run `docker run -it --rm ubuntu: | ||
| + | |||
| + | But what if you **do** want to preserve what you've installed? That's where `docker commit` and `docker build` commands come in, but that comes later. | ||
| + | |||
| + | ## Concepts | ||
| + | ### Images | ||
| + | Docker images are predefined environments. You run an application within these predefined environments with `docker run -it --rm < | ||
| + | |||
| + | Docker images are pulled from https:// | ||
| + | |||
| + | Continuing on the virtual machine analogy, you can think of a docker image as `.iso` file, containing OS installation + system configuration. Running a container is then somewhat like starting a virtual machine, installing an OS with that `.iso`, then running a desired application within that OS. | ||
| + | |||
| + | Docker images are stored in `/ | ||
| + | |||
| + | The following are some image related commands you should remember: | ||
| + | |||
| + | - `docker run -it --rm < | ||
| + | - `docker images` - List docker images on your local filesystem | ||
| + | - `docker rmi < | ||
| + | - `docker pull < | ||
| + | - `docker search < | ||
| + | - `docker tag < | ||
| + | |||
| + | ### Containers | ||
| + | Docker containers are particular instances of an image. If an image is the `.iso` file, a container is the running virtual machine started from it. You can run many containers from the same image simultaneously, | ||
| + | |||
| + | You run a container with `docker run`. The two flags you will use most are `-it` (attach an interactive terminal) and `-d` (run detached, in the background). The `--rm` flag from the Practice section deletes the container automatically when it exits; leave it off when you want the container to stick around. | ||
| + | |||
| + | ``` | ||
| + | docker run -it ubuntu: | ||
| + | docker run -d --name myapp nginx # detached, named " | ||
| + | ``` | ||
| + | |||
| + | Containers that are not running still exist on disk until you delete them. `docker ps` shows only running containers; `docker ps -a` shows all of them, including stopped ones. This is a common source of confusion: you exit a container, it disappears from `docker ps`, but it is still there taking up disk space. | ||
| + | |||
| + | ``` | ||
| + | docker ps # running containers | ||
| + | docker ps -a # all containers, including stopped | ||
| + | docker stop myapp # send SIGTERM, wait, then SIGKILL | ||
| + | docker start myapp # restart a stopped container | ||
| + | docker rm myapp # delete a stopped container | ||
| + | docker rm -f myapp # force-delete a running container | ||
| + | ``` | ||
| + | |||
| + | To run a command inside an already-running container: | ||
| + | |||
| + | ``` | ||
| + | docker exec -it myapp bash # open a shell in the running container | ||
| + | docker exec myapp ls / | ||
| + | ``` | ||
| + | |||
| + | To see what a container printed to stdout/ | ||
| + | |||
| + | ``` | ||
| + | docker logs myapp # print all output so far | ||
| + | docker logs -f myapp # follow output in real time (like tail -f) | ||
| + | ``` | ||
| + | |||
| + | The following are some container-related commands you should remember: | ||
| + | |||
| + | - `docker run -it < | ||
| + | - `docker run -d --name < | ||
| + | - `docker ps` - List running containers | ||
| + | - `docker ps -a` - List all containers including stopped ones | ||
| + | - `docker stop < | ||
| + | - `docker start < | ||
| + | - `docker rm < | ||
| + | - `docker exec -it < | ||
| + | - `docker logs < | ||
| + | |||
| + | ### Volumes | ||
| + | By default everything inside a container is ephemeral: it exists only as long as the container exists, and disappears when you `docker rm` the container. Volumes are how you make data persist beyond the lifetime of a container. | ||
| + | |||
| + | The simplest form is a **bind mount**: you map a directory on your host into a directory inside the container. Whatever is written to that path inside the container is actually written to your host filesystem. | ||
| + | |||
| + | ``` | ||
| + | docker run -it --rm -v / | ||
| + | ``` | ||
| + | |||
| + | Now `/data` inside the container is actually `/ | ||
| + | |||
| + | The other form is a **named volume**: Docker manages the storage location for you, and you refer to it by name. | ||
| + | |||
| + | ``` | ||
| + | docker volume create mydata | ||
| + | docker run -it --rm -v mydata:/ | ||
| + | ``` | ||
| + | |||
| + | Named volumes outlive any particular container. You can mount the same named volume into multiple containers (useful for sharing data between them, though you need to handle concurrent writes yourself). | ||
| + | |||
| + | ``` | ||
| + | docker volume ls # list named volumes | ||
| + | docker volume inspect mydata | ||
| + | docker volume rm mydata | ||
| + | ``` | ||
| + | |||
| + | The key commands: | ||
| + | |||
| + | - `docker run -v / | ||
| + | - `docker run -v < | ||
| + | - `docker volume create < | ||
| + | - `docker volume ls` - List named volumes | ||
| + | - `docker volume rm < | ||
| + | |||
| + | ### Dockerfile | ||
| + | So far you have been running images that other people built. A Dockerfile is how you build your own. It is a plain text file that lists the steps to construct an image, starting from a base image and layering changes on top. | ||
| + | |||
| + | ``` | ||
| + | FROM ubuntu: | ||
| + | |||
| + | RUN apt-get update && apt-get install -y gcc make | ||
| + | |||
| + | COPY . /app | ||
| + | WORKDIR /app | ||
| + | |||
| + | RUN make | ||
| + | |||
| + | CMD [" | ||
| + | ``` | ||
| + | |||
| + | Each instruction (`FROM`, `RUN`, `COPY`, ...) adds a layer on top of the previous one. Docker caches layers: if you rebuild and only the last `RUN` changed, Docker reuses all the cached layers up to that point and only re-executes from the change onward. This is why `apt-get update && apt-get install` should always be in one `RUN` instruction — splitting them means the install can run against a stale cached update layer. | ||
| + | |||
| + | You build the image with `docker build`: | ||
| + | |||
| + | ``` | ||
| + | docker build -t myimage: | ||
| + | docker build -t myimage: | ||
| + | ``` | ||
| + | |||
| + | The `.` at the end is the **build context**: the directory Docker sends to the daemon to use in `COPY` instructions. Keep large files out of it (or list them in `.dockerignore`) because the entire build context is transferred on every build. | ||
| + | |||
| + | Common Dockerfile instructions: | ||
| + | |||
| + | - `FROM < | ||
| + | - `RUN < | ||
| + | - `COPY <src> < | ||
| + | - `WORKDIR < | ||
| + | - `ENV < | ||
| + | - `EXPOSE < | ||
| + | - `CMD [" | ||
| + | |||
| + | The following are some build-related commands: | ||
| + | |||
| + | - `docker build -t < | ||
| + | - `docker commit < | ||
| + | - `docker history < | ||
| + | |||
| + | ### docker compose | ||
| + | Real applications rarely run as a single container. A web application might need a container for the app itself, one for the database, and one for a cache. Docker Compose lets you define all of them in a single `docker-compose.yml` file and bring them all up with one command. | ||
| + | |||
| + | ```yaml | ||
| + | # docker-compose.yml | ||
| + | services: | ||
| + | web: | ||
| + | build: . | ||
| + | ports: | ||
| + | - " | ||
| + | depends_on: | ||
| + | - db | ||
| + | db: | ||
| + | image: postgres:16 | ||
| + | environment: | ||
| + | POSTGRES_PASSWORD: | ||
| + | volumes: | ||
| + | - pgdata:/ | ||
| + | |||
| + | volumes: | ||
| + | pgdata: | ||
| + | ``` | ||
| + | |||
| + | ``` | ||
| + | docker compose up # build images (if needed) and start all containers | ||
| + | docker compose up -d # same, but detached | ||
| + | docker compose down # stop and remove all containers (volumes are kept) | ||
| + | docker compose down -v # also delete volumes | ||
| + | docker compose logs -f # follow logs from all services | ||
| + | docker compose exec web bash # open a shell in the running " | ||
| + | ``` | ||
| + | |||
| + | Compose automatically creates a shared network for all services, so the `web` container can reach the database simply by using the service name `db` as the hostname. Service names in `docker-compose.yml` are the DNS names inside the Compose network. | ||
| + | |||
| + | The key commands: | ||
| + | |||
| + | - `docker compose up` - Start all services defined in `docker-compose.yml` | ||
| + | - `docker compose down` - Stop and remove all services | ||
| + | - `docker compose ps` - Show the status of all services | ||
| + | - `docker compose logs -f` - Follow logs from all services | ||
| + | - `docker compose exec < | ||
| + | - `docker compose build` - Rebuild images without starting containers | ||
| + | |||
