Virtual Party Space Devlog #19: Containerizing an app
Today I finally turned my app into a Docker container, by reverse engineering how the Jitsi Dockerfiles work.
Log
- tried using
--local
context for docker compose CLI, doesn’t seem to do anything useful- doesn’t recreate the cloudmap service discovery, so back to services not talking to each another
- try creating network aliases that use cloudmap format, to see if can pinpoint issue?
- worried it might be related to lacking host ip, and really don’t know how to address not knowing public ip in advance
- dockerizing own app
- currently only been running in dev mode, need to set up a container with nginx etc
- can probably crib a lot from docker-jitsi-meet web container
- Dockerfile tips
- https://docs.docker.com/develop/dev-best-practices/
- https://cloud.google.com/solutions/best-practices-for-building-containers
- https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
- Tutorial for turning web app into container with multi-stage dockerfile
HOW DOES DOCKER-JISI-MEET WORK?
- project contains a
base
image built on debian:buster-slim which contains:- apt-transport-https apt-utils ca-certificates gnupg wget
- s6 for process management (via an “overlay”) https://github.com/just-containers/s6-overlay
- Jitsi’s GPG keys (what for?)
frep
templating tool https://github.com/subchen/frep- a couple wrapper commands
apt-dpkg-wrap
,apt-cleanup
, andtpl
to be used in the other dockerfiles - if built using the
unstable
release, also installs jq procps curl vim iputils-ping net-tools
- base image sets
apt-get
sources for debian and jitsi packages (so if want to use custom source, will have to add new) - each container image extends base by installing at least one jitsi package and some public packages
- uses the wrapper commands from base image for installing and cleanup
- web uses
ADD
docker command instead of apt-get for acme, maybe not available in apt?
- each service contains a
rootfs
folder containing config for the serviceetc
is mostly process running directions for s6cont-init.d
contains bash script to run when the container initializesservices.d
contains run commands for processes that run in this service
defaults
is templates for things like nginx configs, including environment variables- these templates are expanded into the mapped
/config
directory using thetpl
wrapper command aroundfrep
- these templates are expanded into the mapped
- upon container start, s6 runs
10-config
init script, which containstpl
commands to recreate/config
files from/defaults
web
container runs nginx and a cron that runs Lets Encrypt regularly
more about whether to use volumes or not
- “By default all files created inside a container are stored on a writable container layer” https://docs.docker.com/storage/
- not persistent when container goes down
- hard to move to other hosts
- storage driver reduces performance
- for the most part, contents of volumes are just config files that are written every time the container starts
- probably no need to use persistent storage, but also no need to copy in files
- Let’s Encrypt certificates do need to be persisted
trying new, more ECS-friendly setup for docker-jitsi-meet
- renamed network aliases to what CloudMap will call them–seems to work locally, TBD remote
- need to think about setting URIs etc in my app via environment variables
- https://medium.com/chingu/an-introduction-to-environment-variables-and-how-to-use-them-f602f66d15fa
- dotenv library caused an error because I’m building for web, not node. Tried dotenv-webpack instead
- https://github.com/webpack-contrib/css-loader/issues/447
- https://www.npmjs.com/package/dotenv-webpack
Bug fixes
- getting “Bridge Channel send: no opened channel.” error a bunch, but doesn’t seem to actually be any configuration problem & went away on its own.
- this usually means the UDP port for the JVB server isn’t accessible
- may correlate to “WARNING: Took <##> ms to handle IQ:” messages in JVB log?
- found source of non-player avatar not moving when browser tab not focused bug
- Most browsers pause activity when tab isn’t focused, so best case is to detect either blur/focus or pause/resume and change movement behaviour based on state
- https://phaser.discourse.group/t/code-execution-when-coming-back-from-another-tab/1403
- https://photonstorm.github.io/phaser3-docs/Phaser.Core.Events.html
The perils of libraries
- Made some quick progress with dockerizing, but got blocked on Calla not being able to be included in any normal way
- npm file:.. syntax being outside the Docker context was an issue, as expected
- internet suggestion to use Dockerfile in parent directory was a nightmare because entire
projects
directory gets loaded in as context, which is many Gb (still didn’t work) - tried including as tar.gz but kept running into issues with the
my-rollup
dev dependency- I think this was actually due to
package-lock.json
, and might have worked in the end
- I think this was actually due to
- Chosen path: turn Calla into a proper dependency (and by extension, its dependencies
kudzu
andmy-rollup
)- using Verdaccio as local npm repository
- (set as my default repository, remember this when working on other projects)
- had to “log in”, created account and put in password manager
- look up how to publish packages (
npm publish
) - use
npm pack
onmy-rollup
because it’s just a build script I don’t ever want to touch or use - publish
kudzu
to verdaccio - publish
calla
to verdaccio - install still fails due to complaining about some typescript syntax, because package contains TS
- look into how you’re supposed to publish TS
- Calla doesn’t use an outDir, so js files are intermingled with ts files
- edit tsconfig, publish from ./dist folder (remember to actually include folder!)
- app still can’t find calla, because
main
was set incorrectly in package.json Calla.js
was incorrectly capitalized because I was trying to cheat and reuse thedist
directory, which already hadcalla.js
- (this is going to be a problem if I accidentally run the build script instead of just
tsc
)
- (this is going to be a problem if I accidentally run the build script instead of just
- using Verdaccio as local npm repository
Additional configuration
- got all the server stuff in the same docker-compose as my app, just need to get the extra nginx stuff working
- nginx configs contain environment variables, which need to get replaced with env vars passed in Docker build
- jitsi containers use
frep
for env variable replacements, could do that, but requires learning to start a script envsubstr
is a linux cli tool for replacing env vars, still requires a bit of scripting- nginx alpine image supports
envsubstr
automatically starting in 1.19 (mainline, not stable)- could potentially replace valid nginx confs that start with $
- lets encrypt certificates are good for 90 days, so I only need to get one once and store on volume
- made sure local lib-jitsi-meet got loaded so Calla doesn’t try to download it again
- struggled with HTTPS for SO LONG and it looks like the problem was just reusing ports that another container was using.
- copied over more of the jitsi web configs, probably didn’t need to do that
- changing ports instantly worked
About this series
Back in mid-December I started an ambitious project to create a custom platform for a virtual birthday party in February. I kept notes on my progress, both for personal reference and to turn into a series of blog posts. It quickly became apparent that I did not have time to both do the project and blog about the project. I have retroactively decided to post my raw notes as a dev log.