This is self-content code to generate the 3 Musketeers demo with charmbracelet/vhs.
- Docker
- Compose
- Make
- GitHub account
- GitHub fine-grained personal access token
- Token access
- Only select repositories
- Contents: Read and Write
- Metadata: Read-only
- Token access
# Create a .env file and modify it with the correct values
# All variables are required but does not mean they are all used at once
make envfile
# Build dependencies such as the Docker image
make deps
# Test the code
make test
# Record the demo
make record
# Publish the demo to its own orphan branch
make publish
# Clean up
make prune
graph TB
make-record[make record]-->|1\ndocker compose run vhs demo.tape|host-docker-client[Docker client]
host-docker-client-->|2|docker-daemon((Docker daemon))
subgraph vhs-local-container [Container: 3musketeers-vhs:local]
vhs[vhs demo.tape]-->|4|make-run["cd app/
make run"]
make-run-->|5\ndocker compose run golang go run main.go|docker-client[Docker client]
end
docker-daemon-->|3|vhs-local-container
docker-client-->|6|docker-daemon
dir-demo{{"**Host directory: ./**
Dockerfile
Makefile
demo.tape
compose.yml
app/Makefile
app/compose.yml
..."}}
vhs-local-container-...->|volume:bind\n./ <-> /opt/demo/|dir-demo
docker-daemon-->|7|golang-alpine-container
subgraph golang-alpine-container [Container: golang:alpine]
go-run[go run main.go]
end
dir-demo-app{{"**Host directory: app/**
main.go
..."}}
golang-alpine-container-.->|volume:bind\napp/ <-> /opt/app/|dir-demo-app
go-run-->|8|hello-world[/'Hello, World!'/]
vhs-->|9\nouput/demo.gif|dir-demo
Flow:
make record
sends the commanddocker compose run vhs demo.tape
with the Docker client.- The Docker client sends it to the Docker daemon.
- The Docker daemon creates a service
vhs
.- The details of the service is defined in
compose.yml
. - The container is based on Docker image
flemay/3musketeers-vhs:local
. - The image
flemay/3musketeers-vhs:local
definition comes fromDockerfile
. It is based onghcr.io/charmbracelet/vhs
and adds required tools for the demo such as:nvim
,make
,docker
, andcompose
. - A volume is created which maps the host directory
./
to container directory/opt/demo/
. This makes the filedemo.tape
accessible tovhs
inside the container. vhs demo.tape
is then executed.
- The details of the service is defined in
vhs demo.tape
calls the commandscd app/
andmake run
.make run
executes the commanddocker compose golang go run main.go
with the Docker client (inside the container).- The Docker client (inside the container) passes the command to Docker daemon (on the host).
- This is possible because the service
vhs
(defined incompose.yml
) mounts the host/var/run/docker.sock
.
- This is possible because the service
- The Docker daemon creates a service
golang
.- The container is based on the official Go Docker image.
- The details of the service is in
app/compose.yml
. - The service
golang
defines a volume that maps the host directoryapp/
to the container directory/opt/app/
. That directory contains the source filemain.go
.- It is important to note that the full path to the host directory
app/
is passed to the service (using environment variableENV_HOST_APP
) and not the container path/opt/demo/app/
even if the command originated from the containervhs
. This is because the Docker daemon (being outside of the container) would not know the location of/opt/demo/app/
. - The variable substitution
${ENV_HOST_APP_DIR:-.}
sets thesource
to the value of the environment variableENV_HOST_APP_DIR
. If not present, it sets it to.
which means current directory. This allows the Go application example to work with and without Docker-outside-of-Docker (DooD).
- It is important to note that the full path to the host directory
go run main.go
is executed inside the container.
Hello, World!
is printed out.vhs
saves the recorddemo.gif
into directory/opt/demo/output/
which is also accessible from the host directory./output/
.