A bit late this month — we’re heads-down on something bigger. But one thing shipped on the way: you can now deploy your own Docker/OCI images to Runway.
Some people prefer building their own images — fair enough, not every workload fits our buildpack scheme. And rebuilding an image you already have is wasteful.
So we added support to deploy pre-built images to Runway. The catch: they need to be hardened. Here’s what that means.
This sounds simpler than it is.
Containers are not virtual machines — they share a kernel with the host. Running as root would put other apps on the platform at risk, so we don’t allow it.
Many images still don’t get this right, even though all it takes is a USER directive in the Dockerfile — plus making sure your software doesn’t try to write into global directories.
Without one, you’ll see:
runway app deploy image docker.io/valkey/valkey:9.1.0
INFO deploying image "docker.io/valkey/valkey:9.1.0" to app "valkey"
ERROR running runway app deploy image docker.io/valkey/valkey:9.1.0:
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│the app needs to have a numerical USER id set in the Dockerfile (e.g. "USER 1000") - running as root is not supported│
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Valkey is a Redis-compatible key-value store and cache. It ships with a more liberal license and works as a drop-in replacement wherever you’d use Redis.
In this tutorial we deploy cleanstart’s Valkey image to Runway. Why cleanstart? They get the basics right — small, lean base images that run as non-root out of the box.
# update the CLI
runway selfupdate
# create an application
runway app create
...
# set the port -> image does not "EXPOSE"
runway app config set PORT=6379
...
# turn off HTTP
runway app route off
# deploy, deploy, deploy!
runway app deploy image ghcr.io/cleanstart-containers/valkey:9.1.0
INFO deploying image "ghcr.io/cleanstart-containers/valkey:9.1.0" to app "my-redis"
app deployment: done
(release v5)
Access your valkey via runway app exec sh:
❯ runway app exec sh
INFO using app "valkey"
/data $ ps aux
PID USER TIME COMMAND
1 clnstrt 0:00 /usr/bin/valkey-server *:6379
12 clnstrt 0:00 sh
18 clnstrt 0:00 ps aux
/data $ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
/data $
To connect from another app, use app-name.app-name.cluster.local:6379.
A few more projects from the cleanstart catalog worth a look:
elasticsearch or solr (Lucene-based full text searching)mariadb or mysql (relational database)memcached (the original cache)nats or kafka (queue)valkey or redisvault (secret storage)consul (key-value storage)/data. And if it doesn’t EXPOSE a port, set PORT yourself.Of course Tailscale is supported as well:
runway app config set TS_AUTHKEY=...
runway app restart
Learn more in the Tailscale guide.
You can also deploy images you built yourself — handy when you have a pre-configured image coming out of your own pipeline.
--platform linux/amd64. Images built on Apple Silicon will not work.Once the image is built and pushed to your private registry, tell Runway where to find it:
echo "some-token" | runway registry app https://registry.example.org/my-project user --password-stdin
Then create and configure the app:
runway app create
...
runway app route off
runway app registry set https://registry.example.org/my-project
runway app deploy image registry.example.org/my-project/super-valkey:version
Learn more:
Thanks for following along. As mentioned up top, we’re in the middle of something larger — hoping to wrap it up this month.