Créer son propre Manager Scaleway avec Docker
Ce tutoriel vous guide dans la mise en place d'une interface graphique (Web) permettant de gérer vos zones DNS en masse et de déployer des instances Debian sécurisées avec Docker Compose en un clic.
Prérequis
- Docker et Docker Compose installés sur votre machine (Windows, Mac ou Linux).
- Un compte Scaleway avec :
- Une Access Key et une Secret Key.
- Un Project ID.
- Un nom de domaine dont les DNS sont gérés chez Scaleway.
Structure du Projet
Créez un dossier nommé scw-manager et disposez les fichiers suivants à l'intérieur :
scw-manager/
├── .env
├── app.py
├── Dockerfile
└── docker-compose.yml
Le fichier de configuration : .env
Ce fichier stocke vos identifiants de manière sécurisée. Remplacez les valeurs par les vôtres.
SCW_ACCESS_KEY=SCWXXXXXXXXXXXXXXXXX
SCW_SECRET_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
SCW_PROJECT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
L'application : app.py
C'est le cœur du manager (utilisant Python et Streamlit). Il gère l'interface, les appels API et l'injection du Cloud-init.
import streamlit as st
import requests
import pandas as pd
import os
# Configuration de la page en mode large
st.set_page_config(page_title="Scaleway Manager", page_icon="🚀", layout="wide")
# CSS pour maximiser l'espace visuel
st.markdown("<style>.block-container { padding: 1rem; }</style>", unsafe_allow_html=True)
# Récupération des secrets depuis l'environnement
DEFAULT_ACCESS = os.getenv("SCW_ACCESS_KEY", "")
DEFAULT_SECRET = os.getenv("SCW_SECRET_KEY", "")
DEFAULT_PROJECT = os.getenv("SCW_PROJECT_ID", "")
# Barre latérale pour l'authentification
st.sidebar.title("🔐 Authentification")
scw_access = st.sidebar.text_input("Access Key ID", value=DEFAULT_ACCESS)
scw_secret = st.sidebar.text_input("Secret Key", type="password", value=DEFAULT_SECRET)
scw_project = st.sidebar.text_input("Project ID", value=DEFAULT_PROJECT)
HEADERS = {"X-Auth-Token": scw_secret, "Content-Type": "application/json"}
def get_dns_records(zone):
all_recs = []
page = 1
while True:
url = f"https://api.scaleway.com/domain/v2beta1/dns-zones/{zone}/records?page={page}&page_size=100"
res = requests.get(url, headers=HEADERS)
if res.status_code != 200: break
data = res.json()
all_recs.extend(data.get("records", []))
if len(all_recs) >= data.get("total_count", 0): break
page += 1
return all_recs
st.title("🛠️ Scaleway Infrastructure Manager")
tab1, tab2 = st.tabs(["🌐 Gestion DNS", "🖥️ Déploiement Instances"])
# --- ONGLET DNS ---
with tab1:
dns_zone = st.text_input("Zone DNS", placeholder="ex: mon-domaine.fr")
if st.button("🔍 Charger la zone"):
recs = get_dns_records(dns_zone)
if recs:
st.dataframe(pd.DataFrame(recs)[['name', 'type', 'data', 'ttl', 'id']], use_container_width=True, height=400)
st.divider()
c1, c2 = st.columns(2)
with c1:
st.subheader("➕ Ajout Individuel")
with st.form("dns_add"):
n, t, d = st.text_input("Nom"), st.selectbox("Type", ["A","AAAA","CNAME","TXT","MX"]), st.text_input("Valeur")
if st.form_submit_button("Ajouter"):
payload = {"changes": [{"add": {"records": [{"name": n, "type": t, "data": d, "ttl": 3600}]}}]}
requests.patch(f"https://api.scaleway.com/domain/v2beta1/dns-zones/{dns_zone}/records", json=payload, headers=HEADERS)
st.success("Record ajouté.")
with c2:
st.subheader("📋 Import en Masse")
bulk = st.text_area("Format: nom type valeur", height=150)
if st.button("🚀 Synchroniser"):
lines = [l.split() for l in bulk.split('\n') if len(l.split()) >= 3]
new_recs = [{"name": p[0], "type": p[1], "data": p[2], "ttl": 3600} for p in lines]
if new_recs:
requests.patch(f"https://api.scaleway.com/domain/v2beta1/dns-zones/{dns_zone}/records", json={"changes": [{"set": {"records": new_recs}}]}, headers=HEADERS)
st.success("Zone mise à jour.")
# --- ONGLET INSTANCES ---
with tab2:
st.header("🚀 Déploiement Instance + App Docker")
col_a, col_b = st.columns(2)
with col_a:
scw_zone = st.radio("Zone", ["fr-par-1", "fr-par-2"], horizontal=True)
server_name = st.text_input("Nom du serveur", "srv-docker-app")
inst_type = st.selectbox("Type", ["PLAY2-PICO", "PLAY2-NANO", "DEV1-S"])
custom_compose = st.text_area("Contenu docker-compose.yml", height=200, placeholder="services:...")
with col_b:
st.info("Inclus : Debian 13 + Docker + UFW + Fail2ban")
if st.button("🔥 CRÉER ET DÉPLOYER"):
with st.spinner("Déploiement en cours..."):
payload = {"name": server_name, "commercial_type": inst_type, "image": "debian_trixie", "project": scw_project, "dynamic_ip_required": True}
url = f"https://api.scaleway.com/instance/v1/zones/{scw_zone}/servers"
r = requests.post(url, json=payload, headers=HEADERS)
if r.status_code == 201:
sid = r.json()['server']['id']
# Préparation du Cloud-init
indented_compose = custom_compose.replace("\n", "\n ")
cloud_init = f"#cloud-config\npackage_update: true\npackages: [ufw, fail2ban, curl, docker.io, docker-compose]\nwrite_files:\n - path: /app/docker-compose.yml\n content: |\n {indented_compose}\nruncmd:\n - ufw allow 22,80,443/tcp\n - ufw --force enable\n - systemctl enable --now docker\n - cd /app && docker-compose up -d"
# Injection User Data
requests.patch(f"{url}/{sid}/user_data/cloud-init", data=cloud_init, headers={"X-Auth-Token": scw_secret, "Content-Type": "text/plain"})
# Power On
requests.post(f"{url}/{sid}/action", json={"action": "poweron"}, headers=HEADERS)
st.success(f"Instance {server_name} lancée !")
else:
st.error(f"Erreur : {r.text}")
st.sidebar.markdown("---")
st.sidebar.caption("Scaleway Manager v2")Le Dockerfile
Ce fichier définit l'environnement Python nécessaire.
FROM python:3.9-slim
WORKDIR /app
RUN pip install streamlit requests pandas
COPY app.py .
EXPOSE 8501
CMD ["streamlit", "run", "app.py", "--server.address=0.0.0.0"]
Le fichier docker-compose.yml
Pour orchestrer le lancement du manager.
services:
scw-manager:
build: .
ports:
- "8501:8501"
env_file:
- .env
restart: unless-stopped
Lancement
- Ouvrez un terminal dans le dossier du projet.
- Accédez à l'interface sur votre navigateur :
http://localhost:8501
Lancez la commande :
docker-compose up --build -d
Note : L'onglet DNS vous permet de gérer vos domaines en masse, et l'onglet Instances déploie une Debian 13 avec votre stack Docker prête à l'emploi.