Deploying docker-hello-world

ជំពូកនេះមិនទាន់ត្រូវបានបកប្រែជាភាសាខ្មែរនៅឡើយទេ — សូមអានជាភាសាអង់គ្លេសខាងក្រោម។

Table of Contents

  1. What this example is for
  2. Run it locally
  3. Build and push the image
  4. Deploy it as a stack
  5. Beginner Pitfalls

1. What this example is for

Run App has no API — there's nothing to wrap in code. docker-hello-world exists to give the dashboard steps from Part 1 something concrete to deploy and configure, not to demonstrate a Run App SDK.

It's a small Express app: a static frontend, a JSON API, and a health endpoint.

const express = require("express");
const path = require("path");

const app = express();
const port = process.env.PORT || 3000;
const message = process.env.APP_MESSAGE || "Hello from Run App!";
const accentColor = process.env.APP_COLOR || "#2563eb";

let visitCount = 0; // in-memory only — resets on restart/redeploy
const startedAt = Date.now();

app.use(express.static(path.join(__dirname, "..", "public")));
app.use(express.json());

app.get("/api/config", (req, res) => {
  res.json({ message, accentColor });
});

app.get("/api/counter", (req, res) => {
  res.json({ count: visitCount });
});

app.post("/api/counter/increment", (req, res) => {
  visitCount += 1;
  res.json({ count: visitCount });
});

app.get("/health", (req, res) => {
  res.json({
    status: "ok",
    uptimeSeconds: Math.floor((Date.now() - startedAt) / 1000),
  });
});

app.listen(port, () => {
  console.log(`Listening on port ${port}, APP_MESSAGE="${message}"`);
});

It reads PORT, APP_MESSAGE, and APP_COLOR — this mirrors Run App's Shared Env / per-service Environment step from Part 1: you set these as env vars when creating the stack and see them reflected once deployed. The visit counter is a plain module-level variable, deliberately in-memory — there's no database service in this series yet, so it exists to make "state" visible and testable, and resets on every container restart or redeploy.

2. Run it locally

nvm use && npm install
npm run dev

Visit http://localhost:3000, click "Visit +1" a few times, then restart the server — the counter resets to 0. Try APP_MESSAGE="hi" APP_COLOR="crimson" npm run dev and refresh to see both change.

3. Build and push the image

The Dockerfile is the only thing Run App actually consumes — you build and push this image to a registry, then reference it in the create-stack wizard:

FROM node:20-alpine

WORKDIR /app

COPY package.json ./
RUN npm install --omit=dev

COPY src ./src
COPY public ./public

EXPOSE 3000

CMD ["node", "src/server.js"]

Run App currently only supports linux/amd64, so build explicitly for that platform even on an Apple Silicon Mac:

docker login

docker buildx build --platform linux/amd64 \
  -t <your-dockerhub-username>/run-app-hello:latest \
  --push .

--push builds and pushes in one step. To inspect the image locally first, load it into Docker instead and push manually:

docker buildx build --platform linux/amd64 \
  -t <your-dockerhub-username>/run-app-hello:latest \
  --load .

docker push <your-dockerhub-username>/run-app-hello:latest

4. Deploy it as a stack

Follow Part 1 to create a stack from <your-dockerhub-username>/run-app-hello:latest, setting APP_MESSAGE and APP_COLOR as Shared Env keys so you can see them reflected once deployed. Optionally continue with Part 3 to attach a custom domain.

5. Beginner Pitfalls

  • Building without --platform linux/amd64 on Apple Silicon. The resulting image is arm64 and won't run on Run App's infrastructure — always build explicitly for linux/amd64.
  • Expecting the visit counter to survive a redeploy. It's in-memory by design — a real persistent counter would need a database service, which isn't part of this series yet.
  • Forgetting to set APP_MESSAGE/APP_COLOR as env vars on the stack. Without them, the app still runs — it just falls back to its defaults — so this is easy to miss rather than error out on.

ទិញកាហ្វេជូនខ្ញុំ

ចូលចិត្តមេរៀននេះមែនទេ? សូមពិចារណាទិញកាហ្វេជូនខ្ញុំមួយកែវ ដើម្បីគាំទ្រការបង្កើតមាតិកាឥតគិតថ្លៃបន្ថែមទៀត!