Technik8 阅读

Mein Einstiegsleitfaden für Kamal2 – das perfekte VPS-Deployment-Tool

Derzeit verwende ich hauptsächlich Next.js 16 und Rails 8 als Full-Stack-Frameworks. Durch die Nutzung von Rails bin ich auf das offiziell empfohlene Deployment-Tool Kamal gestoßen. Normalerweise setze ich es ein, um Projekte auf RN- und Alibaba-Cloud-Servern zu deployen. Es ist sehr einfach und unkompliziert zu bedienen, und jetzt möchte ich euch das Konzept von Kamal2 sowie die grundlegende Einführung und Verwendung vorstellen.

Dieser Artikel wird nicht sofort zu komplexen Inhalten übergehen. Vielmehr möchte ich zuerst die Kernaspekte von Kamal2 klar darlegen: Was es eigentlich ist, wobei es uns hilft, wie man grundsätzlich damit startet und welche die häufigsten Operationen sind. Am Ende gebe ich ein Anwendungsbeispiel mit Next.js, um die zuvor behandelten Konzepte in einem konkreten Projekt zu verankern.

Was ist Kamal2?

Kurz gesagt ist Kamal2 ein Tool, das **Anwendungen per SSH + Docker bereitstellt**. Es bietet keine vollständige Plattform wie Heroku und ist auch kein schweres Orchestrierungssystem wie Kubernetes; vielmehr fasst es das „Bereitstellen einer Gruppe von Docker-Containern“ in einer Reihe wiederholbarer Befehle und Konfigurationen zusammen.

Der Kerngedanke von Kamal ist eigentlich sehr direkt:

Das ist auch der Grund, warum ich Kamal mag. Es führt nicht zu viele zusätzliche Abstraktionen ein – man hat ungefähr eine Vorstellung davon, was es tut, und Probleme sind daher leichter einzugrenzen.

Für welche Szenarien eignet sich Kamal2?

Ich finde, Kamal eignet sich besonders für folgende Situationen:

Mit anderen Worten: Kamal ersetzt nicht Docker, sondern macht Docker-Deployments handlicher.

Zunächst einige grundlegende Konzepte verstehen

Bevor es losgeht, empfehle ich, dir die wichtigsten Konzepte von Kamal zu merken.

config/deploy.yml

Dies ist die Hauptkonfigurationsdatei von Kamal, aus der die Deployment-Konfiguration gelesen wird. Du kannst sie dir als „Bedienungsanleitung für dieses Deployment“ vorstellen: Dienstname, Imagename, Serverliste, Image-Registry, Umgebungsvariablen, Builder, Proxy usw. werden hier festgelegt.

.kamal/secrets

Dies ist der Standardspeicherort für Secrets; Kamal liest sensible Variablen hieraus. Beispielsweise werden Registry-Passwörter oder der RAILS_MASTER_KEY von Rails normalerweise nicht direkt in der deploy.yml hartcodiert, sondern über .kamal/secrets injiziert.

kamal setup

Dies ist der wichtigste Befehl für das erste Deployment. Die Dokumentation beschreibt es klar: Es verbindet sich mit dem Server, installiert Docker (falls nicht vorhanden), meldet sich bei der Registry an, baut das Image, pusht es, zieht es, startet kamal-proxy, startet den neuen Container und leitet den Traffic um, sobald GET /up 200 OK zurückgibt.

kamal deploy

Dies ist der am häufigsten verwendete Befehl für nachfolgende Releases. Nachdem das erste Setup erfolgreich durchgelaufen ist, erfolgen die weiteren Deployments normalerweise mit kamal deploy.

Wie installiert man Kamal2?

Wenn du bereits eine Ruby-Umgebung lokal hast, ist die direkteste Installationsmethode:

bash
gem install kamal

Dies ist die in der offiziellen Dokumentation angegebene Standardinstallationsmethode. Wenn du kein Ruby hast, kannst du auch die Docker-Version von Kamal ausführen, aber die offizielle Dokumentation weist darauf hin, dass diese Methode Einschränkungen hat, daher empfehle ich für den Einstieg die Installation per gem.

Nach der Installation kannst du die Version überprüfen:

bash
kamal version

Ein Projekt initialisieren

Gehe in dein Projektverzeichnis und führe aus:

bash
kamal init

Dieser Befehl initialisiert die für Kamal erforderlichen Basisdateien, am wichtigsten sind config/deploy.yml und .kamal/secrets.

Wenn dein Projekt bereits eine Dockerfile hat, dann hast du bereits eine wichtige Voraussetzung erfüllt. Der Kamal-Deployment-Workflow baut standardmäßig um die Dockerfile im Projektstammverzeichnis herum das Image.

Minimal funktionsfähige Konfiguration

Ich empfehle, beim Einstieg mit einer sehr kleinen config/deploy.yml zu beginnen. Das offizielle Minimalbeispiel der Dokumentation sieht ungefähr so aus:

yaml
service: myapp
image: your-registry-user/myapp

servers:
  - 203.0.113.10

registry:
  username: your-registry-user
  password:
    - KAMAL_REGISTRY_PASSWORD

builder:
  arch: amd64

env:
  secret:
    - AUTH_SECRET

In dieser Konfiguration sind die folgenden Punkte am wichtigsten zu verstehen:

In dieser Phase ist es nicht nötig, eine vollständige Konfiguration anzustreben; es ist wichtiger, sicherzustellen, dass die grundlegendste Pipeline läuft.

Secrets konfigurieren

Als nächstes muss .kamal/secrets vorbereitet werden. Zum Beispiel:

bash
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
AUTH_SECRET=your-auth-secret

Bei Rails-Projekten wird im Dokumentationsbeispiel der RAILS_MASTER_KEY aus config/master.key gelesen. Das ist auch einer der Gründe, warum Rails und Kamal so gut zusammenpassen: Neue Rails-Projekte lassen sich von Natur aus relativ einfach an diese Deployment-Methode anschließen.

Was passiert beim ersten Deployment?

Sobald die Konfiguration und die Secrets bereit sind, kannst du ausführen:

bash
kamal setup

Dieser Befehl erledigt eine Menge, aber du kannst ihn dir als „vollständige Erstbereitstellung“ vorstellen. Laut offizieller Dokumentation führt er mindestens diese Aktionen aus:

  1. Via SSH mit dem Server verbinden.

  2. Falls Docker auf dem Server fehlt, wird es automatisch installiert.

  3. Lokal und auf dem Server bei der Registry anmelden.

  4. Das Image mit der Dockerfile im Projektstammverzeichnis bauen.

  5. Das Image in die Registry pushen.

  6. Den Server das Image pullen lassen.

  7. Sicherstellen, dass kamal-proxy auf Port 80/443 läuft.

  8. Den neuen Container starten.

  9. Warten, bis GET /up 200 OK zurückgibt.

  10. Den Traffic auf den neuen Container umleiten.

  11. Den alten Container stoppen und nicht mehr benötigte Images sowie gestoppte Container bereinigen.

Hier gibt es einen sehr wichtigen Punkt: **Der Health-Check ist standardmäßig GET /up**. Deine Anwendung sollte also am besten einen solchen einfachen Health-Check-Endpunkt haben, sonst könnte der neue Container zwar gestartet sein, aber Kamal leitet trotzdem keinen Traffic um.

Spätere Deployments sind viel einfacher

Nachdem das erste Setup erfolgreich war, reicht für spätere Updates normalerweise:

bash
kamal deploy

Die Dokumentation hat dies bereits als Befehl für nachfolgende Deployments festgelegt. Du kannst ihn dir als „normalen Release-Einstieg“ vorstellen: Image neu bauen, pushen, pullen, neuen Container starten, Health-Check durchführen, Traffic umleiten, alten Container stoppen.

Aus Nutzersicht ist das Angenehmste an Kamal, dass das erste Deployment etwas mehr Vorbereitung erfordert, danach läuft es aber sehr stabil.

Häufige Operationen

Für den Einstieg finde ich diese Befehle am nützlichsten:

Initialisierung

bash
kamal init

Erzeugt die grundlegenden Deployment-Dateien.

Erstes Deployment

bash
kamal setup

Bringt den Server, Docker, das Image, den Proxy und die Anwendung zum ersten Mal insgesamt zum Laufen.

Spätere Releases

bash
kamal deploy

Der im Alltag am häufigsten verwendete Befehl.

Multi-Umgebung-Deployment

Wenn du später zwischen staging und production unterscheiden möchtest, unterstützt Kamal die Angabe eines Ziels mit -d, z. B.:

bash
kamal deploy -d staging

Die offizielle Dokumentation erklärt, dass Kamal dann config/deploy.staging.yml zusammen mit der Basiskonfiguration verwendet.

Diese Funktion ist sehr nützlich, aber wenn du gerade erst anfängst, reicht es, von ihrer Existenz zu wissen – du musst sie noch nicht sofort anwenden.

Warum passt es gut zu Rails?

Neue Rails 8-Projekte bringen normalerweise bereits eine Dockerfile mit, und der Kamal-Deployment-Workflow baut genau darauf auf. Hinzu kommt, dass das Rails-Ökosystem natürlicherweise Ruby-gem-basierte Tools akzeptiert, sodass der Weg von Rails zu Kamal fast selbstverständlich ist.

Für mich persönlich war es genau so: Weil ich zuerst in einem Rails-Projekt auf diese Methode gestoßen bin, habe ich angefangen, Kamal ernsthaft als langfristig nutzbare Deployment-Lösung zu betrachten.

Ein Einsteigerbeispiel mit Next.js

Zum Schluss ein Beispiel, das meinem Alltag näher kommt: Wenn ich Kamal zum Deployment eines Next.js-Projekts verwenden möchte, mache ich es in der Regel zu einer standardmäßigen Docker-Anwendung und übergebe sie dann an Kamal zur Veröffentlichung.

Schritt 1: Next.js output auf standalone setzen

Die Next.js-Dokumentation erklärt, dass nach dem Aktivieren von output: 'standalone' das Build-Ergebnis ein .next/standalone-Verzeichnis erzeugt, das die minimal erforderlichen Dateien für den Betrieb und eine server.js enthält. Dies eignet sich hervorragend für Docker-Deployments, da nicht die gesamte Entwicklungsumgebung unverändert mitgenommen werden muss.

In der next.config.js kann das so aussehen:

js
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
}

module.exports = nextConfig

Beachte: Die Next.js-Dokumentation weist darauf hin, dass output: 'standalone' eher zur direkten Nutzung der erzeugten server.js gedacht ist und nicht zur weiteren Verwendung von next start.

Schritt 2: Dockerfile vorbereiten

Eine einfache Next.js-Dockerfile könnte so aussehen:

Dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]

Der Schwerpunkt liegt hier nicht auf den Docker-Tricks an sich, sondern auf dem Gedanken: **Zuerst Next.js zu einem standardmäßigen, ausführbaren Container machen, dann Kamal das Deployment übernehmen lassen.**

Schritt 3: Kamal-Konfiguration schreiben

Zum Beispiel:

yaml
service: my-next-app
image: your-registry-user/my-next-app

servers:
  - 203.0.113.10

registry:
  username: your-registry-user
  password:
    - KAMAL_REGISTRY_PASSWORD

builder:
  arch: amd64

env:
  clear:
    PORT: 3000
    NODE_ENV: production

Die Logik dieser Konfiguration ist einfach:

Schritt 4: Einen Health-Check-Endpunkt hinzufügen

Da Kamal standardmäßig GET /up prüft, füge ich in Next.js eine einfache Route hinzu, z. B. unter App Router:

ts
export async function GET() {
  return Response.json({ ok: true })
}

Lege sie z. B. unter app/up/route.ts ab, damit /up eine einfache Erfolgsantwort zurückgibt. Je leichter dieser Endpunkt, desto besser – der Zweck ist nur, Kamal mitzuteilen: Der Container ist bereit, Traffic zu empfangen.

Schritt 5: Deployment

Zum Schluss kehren wir zum Standard-Kamal-Workflow zurück:

bash
kamal setup

Spätere Updates:

bash
kamal deploy

Wenn dieser Ablauf bei einem Next.js-Projekt stabil läuft, wirst du feststellen: Kamal kümmert sich nicht darum, ob du Rails verwendest; es kommt wirklich nur darauf an, dass du **ein standardmäßiges Docker-Image bereitstellen kannst, und einen Webdienst, der seinen Gesundheitszustand prüfen lässt**.

An dieser Stelle erstmal genug

Wenn du, wie ich, über Rails 8 zu Kamal gekommen bist und diese Methode dann nach und nach auf Next.js 16-Projekte übertragen hast, dann ist die Positionierung von Kamal2 leicht zu verstehen: Es ist keine Plattform, sondern ein Werkzeug, das selbst gehostete Docker-Deployments geordneter macht.

Für den Einstieg reicht es, diese Punkte zu beherrschen:

Wenn diese Dinge flüssig laufen, kannst du dich später mit Multi-Umgebung, Accessories, Hooks, komplexen Proxy-Konfigurationen usw. befassen – das fällt dann leichter.

Teilen

Teilen

Diesen Artikel teilen.