Erlang cluster on Kubernetes: Initial Deployment
For simplicity’s sake, I created a new application with
rebar3 new app name=erlclu. I very soon regretted this
decision, because I actually needed a release, so I ran
rebar3 new release name=whoops and manually merged the relevant
Creating a new container image
That needs a
Dockerfile; I’ll start with a two-stage alpine-based image, as follows:
FROM docker.io/erlang:18.104.22.168-alpine AS build COPY / /build WORKDIR /build RUN rebar3 as prod release # FROM docker.io/alpine RUN apk add --no-cache openssl && \ apk add --no-cache ncurses-libs && \ apk add --no-cache libstdc++ COPY --from=build /build/_build/prod/rel/erlclu /erlclu EXPOSE 8080 ENTRYPOINT ["/erlclu/bin/erlclu", "foreground"]
It uses an
erlang:alpine image as the base, and runs
rebar3 release to build the release. That’s then copied into a
alpine image to be deployed. Erlang requires a few dependencies to be installed (the
apk add commands).
ENTRYPOINT runs the release in the foreground.
I’m doing this on my Windows laptop, using WSL2 and I’ve got Docker Desktop installed. Because I can’t figure out how to get Docker Desktop to trust the private CA on my cluster’s docker registry, I’m using podman instead.
That ends up looking like this:
RELEASE_VSN ?= 0.1.0 DOCKER_REGISTRY ?= docker.k3s.differentpla.net all: build-image push-image release: rebar3 as prod release build-image: podman build -f Dockerfile -t erlclu push-image: podman push erlclu $(DOCKER_REGISTRY)/erlclu:$(RELEASE_VERSION)
Nothing particularly surprising here. There’s an extra
release target so that I can run it locally.
apiVersion: apps/v1 kind: Deployment metadata: name: erlclu namespace: erlclu spec: replicas: 1 selector: matchLabels: app: erlclu template: metadata: labels: app: erlclu spec: containers: - name: erlclu image: docker.k3s.differentpla.net/erlclu:0.1.0 imagePullPolicy: Always resources: limits: memory: "128Mi" cpu: "500m" ports: - containerPort: 8080
The only things of note here are:
- I’ve set
imagePullPolicy: Always, because I’ve not particularly thought about versioning the container image, so it’s better for nodes to pull a fresh image every time.
- I’ve set some basic resource limits.
If you look at the initial-deployment tag,
you’ll see that I just stuck the
k8s directory inside the
This is probably a mistake: the K8s application will eventually have a bunch of other things in it (init containers, cronjobs, etc.), and it would make more sense to have it at the top-level.