Docker
Docker is a tool that makes getting up and running with developing software including web applications easy, and it can also make deploying the software to servers easier too. The dependencies and the way they interact with each other as services is described in the project code itself. The Dockerfile is the instructions to Docker to create an image for the application logic code. The image then creates a container, which is sort of a runtime environment for the application logic, with its own filesystem that you can get a Bash shell inside of to look around if you want. Docker Compose is a tool that starts up multiple containers at once as a network of services. Anki Books does have a Dockerfile and docker-compose.yml file for Docker Compose, and I have been able to use the app in containers locally.
This is the Dockerfile at time of writing:
FROM ruby:3.2.1 RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends libvips libvips-tools COPY . /usr/src/app WORKDIR /usr/src/app RUN bundle install CMD ["passenger", "start"]
It starts by downloading an existing image with ruby 3.2.1 that the image it is describing will extend. It installs some stuff including libvips which is a dependency for Active Storage in Rails. It copies the working directory at the location of the Dockerfile in the host computer into the filesystem of the image at /usr/src/app. The WORKDIR command is like cd in Bash, making that the working directory. Then it does a bundle install to install the Ruby dependencies and finally, starts up the application logic by invoking the application server, Passenger.
docker-compose.yml:
version: '3' services: web: build: . ports: - "3000:3000" volumes: - .:/usr/src/app - exclude_tmp:/usr/src/app/tmp environment: DATABASE_HOST: database POSTGRES_USER: postgres POSTGRES_PASSWORD: 1234asdf!!!! POSTGRES_DB: anki_books_development database: image: postgres:14 volumes: - data:/var/lib/postgresql/data environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: 1234asdf!!!! POSTGRES_DB: anki_books_development volumes: exclude_tmp: data:
This sets up two services (it is a network of two containers). One is for the application logic, and one is for the PostgreSQL database. The database service specifies the image to use by name, and the web service is using the Dockerfile it finds in the same directory. There is a mapping between port 3000 of the host machine and port 3000 of the container running the web service. When your web browser makes a request to your local machine IP address (127.0.0.1 or localhost) at port 3000 which is standard for a Rails app run locally in development, it is forwarded to the container, inside which has a Rails app listening at the same port. The volumes are named volumes and are persistent, shared places in the filesystem of the host machine and container that Docker manages for you. There are also environment variables being set, for example the name of the database, and the name and password of the database role that the application logic will use to connect to the database.
To understand the environment variables, this part of the config/database.yml is relevant:
default: &default adapter: postgresql encoding: unicode # For details on connection pooling, see Rails configuration guide # https://guides.rubyonrails.org/configuring.html#database-pooling pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: <<: *default database: anki_books_development # The TCP port the server listens on. Defaults to 5432. port: 5432 # # To use Docker Compose to run the app (`$ docker compose up`) # uncomment (including ERB <%# comments) and use the following: # # host: <%# ENV.fetch("DATABASE_HOST") %> # database: <%# ENV.fetch("POSTGRES_DB") %> # The specified database role being used to connect to postgres. # To create additional roles in postgres see `$ createuser --help`. # When left blank, postgres will use the default role. This is # the same name as the operating system user running Rails. # username: <%# ENV.fetch("POSTGRES_USER") %> # The password associated with the postgres role (username). # password: <%# ENV.fetch("POSTGRES_PASSWORD") %>
The issue I had with Docker was my computer having only 256 Gb of storage. I am using the Windows Subsystem for Linux 2, and it seems to use more storage over time and not give it back, until I do this manual thing that gives me back about 15 Gb from it. I uninstalled a lot of programs to get storage and Docker Desktop was too juicy to not uninstall. I may have been using it in a way that made it use a lot of storage though.
Article notes
What in Docker can be thought of as just an empty vessel for executing software in?
A container
What is an object-oriented programming metaphor for containers and images in Docker?
(Images = ?, containers = ?)
Images = classes, containers = objects
What is the default user inside of a Docker container?
root
What command is essentially the Docker CLI?
docker
On what operating systems must the Docker daemon be run inside a lightweight Linux virtual machine?
Mac and Windows