Wdróż aplikację Windmill na Pethost jednym kliknięciem
Skrypty, flow i aplikacje w Pythonie, TypeScripcie, Go, SQL lub Bashu, uruchamiane przez workery według harmonogramu, webhookiem albo przyciskiem
Co się dzieje
- Logujesz się do Pethost albo zakładasz konto, kluczem dostępu, przez GitHub albo Google.
- Nie masz jeszcze maszyny? Wybierasz plan, a my ją dla ciebie przygotowujemy. Link czeka w twojej przeglądarce, aż będzie gotowa.
- Okno „Nowy projekt” otwiera się na tej aplikacji. Wypełniasz to, o co prosi, i klikasz „Utwórz projekt”: E-mail, Hasło administratora.
- Za minutę czy dwie aplikacja działa pod własnym adresem z HTTPS. Jej sekrety są tworzone losowo, a dane trafiają do nocnego backupu.
- To projekt jak każdy inny: jego compose.yaml, .env, logi i terminal są w panelu, a twój agent może go zmienić, cofnąć do wcześniejszej wersji albo przywrócić.
Pierwsze kroki
Zaloguj się adresem e-mail i hasłem administratora, które podano: Windmill tworzy tego superadmina przy pierwszym starcie. Utwórz workspace, a potem skrypt albo flow; jego pakiety instalują się przy pierwszym uruchomieniu.
Co uruchamia
Szablon to ten compose.yaml i zmienne, które zapisuje do .env projektu. Pethost uruchamia plik dokładnie tak, jak jest napisany.
services:
windmill_server:
image: ghcr.io/windmill-labs/windmill:1.835.0
restart: unless-stopped
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@db/windmill?sslmode=disable
MODE: server
BASE_URL: ${URL}
ADMIN_EMAIL: ${ADMIN_EMAIL}
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
# A new Windmill signs anyone in as [email protected] / changeme. So, before it answers on its
# own port, it is started on one nobody reaches, the email and password asked are made its
# superadmin, and the stock account is deleted.
command:
- sh
- -c
- |
PORT=8001 windmill &
setup=$$!
node -e '
const base = "http://127.0.0.1:8001/api";
const json = { "Content-Type": "application/json" };
const login = (email, password) => fetch(base + "/auth/login", { method: "POST", headers: json, body: JSON.stringify({ email, password }) });
const replaceStock = async (token) => {
const auth = { ...json, Authorization: "Bearer " + token };
const account = { email: process.env.ADMIN_EMAIL, password: process.env.ADMIN_PASSWORD, super_admin: true, name: "Admin" };
await fetch(base + "/users/create", { method: "POST", headers: auth, body: JSON.stringify(account) });
const mine = await login(account.email, account.password);
if (!mine.ok) throw new Error("the new superadmin cannot sign in: " + (await mine.text()));
const gone = await fetch(base + "/users/delete/[email protected]", { method: "DELETE", headers: { Authorization: "Bearer " + (await mine.text()) } });
if (!gone.ok) throw new Error("the stock account stays: " + (await gone.text()));
};
const run = async () => {
for (let i = 0; i < 300; i++) {
try {
const stock = await login("[email protected]", "changeme");
if (stock.status === 400 || stock.status === 401) return;
if (stock.ok) return await replaceStock(await stock.text());
} catch (error) {
if (String(error).includes("Error:")) console.error(String(error));
}
await new Promise((done) => setTimeout(done, 1000));
}
process.exit(1);
};
run().catch((error) => { console.error(String(error)); process.exit(1); });
' || exit 1
kill $$setup
wait $$setup
exec windmill
volumes:
- worker_logs:/tmp/windmill/logs
depends_on:
db:
condition: service_healthy
windmill_worker:
image: ghcr.io/windmill-labs/windmill:1.835.0
restart: unless-stopped
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@db/windmill?sslmode=disable
MODE: worker
WORKER_GROUP: default
volumes:
- worker_dependency_cache:/tmp/windmill/cache
- worker_logs:/tmp/windmill/logs
depends_on:
db:
condition: service_healthy
# Runs the light "native" jobs (HTTP and SQL steps) in process.
windmill_worker_native:
image: ghcr.io/windmill-labs/windmill:1.835.0
restart: unless-stopped
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@db/windmill?sslmode=disable
MODE: worker
WORKER_GROUP: native
NATIVE_MODE: "true"
SLEEP_QUEUE: "200"
volumes:
- worker_logs:/tmp/windmill/logs
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
restart: unless-stopped
shm_size: 1g
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: windmill
volumes:
- db_data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 10
volumes:
db_data:
worker_dependency_cache:
worker_logs: