AI 资讯
Gubernator v2.13.0: Google SRE SLOs, Native CoreDNS Suite & Caddy Ingress for Docker Compose
If you love the simplicity of Docker Swarm (native Compose files, lightweight single binary) but miss the advanced capabilities of Kubernetes (targeted label placement, SRE-grade observability, built-in DNS service discovery, and zero-trust ingress), meet Gubernator (gbnt) . We are excited to release Gubernator v2.13.0 , introducing three massive feature suites natively integrated into a single binary and a modern Material Design 3 Flutter Web Dashboard: Google SRE Multi-Burn-Rate SLO Engine & Interactive Suite CoreDNS 4-Tab Management Suite & Interactive Dig Playground Caddy Ingress & Zero-Trust Reverse Proxy Suite Fun Fact: The entirety of Gubernator's codebase, multi-node deployment pipelines, and SRE features were designed, built, and pair-programmed using **Google Antigravity (AGY) , Google DeepMind's agentic AI coding assistant! Let's dive into what's new and how you can level up your self-hosted or production container clusters! 1. Google SRE Multi-Burn-Rate SLO Engine & Web Suite Defining Service Level Objectives (SLOs) and tracking Error Budgets is the gold standard of Site Reliability Engineering. Until now, implementing SLOs meant running heavy Kubernetes CRDs (via tools like Sloth or Pyrra) or using costly SaaS platforms. Gubernator v2.13.0 brings Google SRE Workbook (Chapter 5) compliant multi-burn-rate alerting straight to simple docker-compose.yml services: version : " 3.8" services : payment-api : image : hashicorp/http-echo:latest labels : gbnt.slo.enable : " true" gbnt.slo.target : " 99.9" gbnt.slo.window : " 30d" gbnt.slo.template : " caddy-http" gbnt.slo.journey : " Checkout Flow" What makes Gubernator's SLO Suite unique? Google Multi-Burn-Rate Alerting : Automatically generates standard 4-window Prometheus recording and alert rules ( Critical Page 1h/6h & Warning Ticket 3d/14d ). Dynamic "No-Code" Management : Click "+ Configure / Add SLO" in the Web UI or call POST /v1/slo/edit to create, edit, or disable SLOs on the fly without editing Compose
AI 资讯
Why Spark Couldn't Read from Kafka: A Real Debugging Journey Across PySpark, Hadoop, Docker, and Kafka
I thought this would be a simple task. I already had a Python Kafka producer running. Kafka was up in Docker. The topic existed, and I could send a message into it successfully. The next step sounded straightforward: Python Producer ↓ Kafka ↓ Spark Structured Streaming All I wanted Spark to do was read a JSON message from a Kafka topic. Instead, I ran into one error after another. At first, it looked like one problem: Spark cannot read Kafka. It was not one problem. It turned into a chain of failures across several different layers: Python / PySpark ↓ Spark runtime ↓ Kafka connector ↓ Hadoop / Windows ↓ Docker ↓ Kafka networking ↓ Ivy dependency resolution The useful part of this experience was not any single fix. It was learning how to separate the layers and stop treating every error as a problem in my Python code. This is the full debugging path. What I Was Building This was part of an financial data engineering project. The batch side of the project already looked roughly like this: Financial Data Source ↓ Python ingestion ↓ AWS S3 ↓ Snowflake ↓ dbt ↓ Financial anomaly models I wanted to add a streaming extension for newly arriving financial events. For the first version, I kept it intentionally simple: Python Kafka Producer ↓ Kafka topic: financial_events ↓ Spark Structured Streaming The producer sent a simulated financial event: { "company_id" : "COMPANY_001" , "company_name" : "Sample Company" , "report_type" : "quarterly_report" , "reporting_date" : "2026-08-08" , "event_id" : "FIN-20260808-001" , "source" : "simulated_financial_event" } Kafka accepted the message successfully. I could even read it with Kafka's console consumer. So Kafka itself was working. Then Spark entered the picture. Failure #1: PySpark Worked, but spark-submit Didn't I installed PySpark: pip install pyspark Then I installed Java 17 and verified it: java -version After reopening my terminal, Java was available. I tested Spark directly through Python: python -c "from pyspark.sql import S
AI 资讯
My AI Answered in 5.8 Seconds and Said Nothing Useful. I Almost Blamed the Model.
I put an AI into a Google Meet call. It transcribed Japanese, generated a reply, and spoke it out loud. Total new spend: $0 . Then I asked it the one question I actually needed answered, and it said: "I think there's still room for discussion. How about we set up a session to align our understanding?" That is exactly what a person says when they don't know. TL;DR: I had a latency problem and an "is this model smart enough" problem. Neither was real. Same model, same question, 5.80s → 5.68s — 2,545 characters of context turned a deflection into a claim you could argue with. The stack, and what it replaced I wanted an AI participant in a real meeting. Not a note-taker — something that answers when someone demands specifics. The obvious stack bills you three times: a hosted meeting-bot API, a speech-to-text vendor, and a text-to-speech vendor. I replaced all three. Layer Obvious choice What I used Why Meeting bot Recall.ai, $0.50/hour Attendee (OSS, self-hosted) no per-hour billing Speech-to-text Deepgram / AssemblyAI Google Meet's own captions the meeting already generates them Text-to-speech Google Cloud TTS raw audio POST (below) no GCP project at all Reasoning + voice LLM + TTS, two hops Gemini Live (speech-to-speech) one model, one hop Attendee is 699 stars, last pushed 2026-08-07. Google Meet exposes no bot API, so it drives a full Chrome instance — which is why setup hurt before anything else did. The setup tax, compressed Two problems were routine. The image pins FROM --platform=linux/amd64 ubuntu:22.04 , and my machine is Apple Silicon, so colima with Rosetta: colima start --vm-type = vz --vz-rosetta --cpu 6 --memory 12 --disk 60 docker run --rm --platform = linux/amd64 alpine:3.20 uname -m # x86_64, 5.6s cold Then the build died at step 35 of 42 with the --chmod option requires BuildKit — colima's docker CLI ships without the buildx plugin. brew install docker-buildx , point ~/.docker/config.json at /opt/homebrew/lib/docker/cli-plugins via cliPluginsExtraDirs
AI 资讯
Docker for Beginners: Images, Containers, Ports, and Volumes Explained
Docker for Beginners: Images, Containers, Ports, and Volumes Explained If you've ever followed a programming tutorial and seen something like: docker run ... you've probably wondered: What exactly is Docker doing? I had the same question when I started learning Docker. At first, I thought Docker was simply a way to "run applications in containers." But there is much more to it. Once I understood four concepts — images, containers, ports, and volumes — Docker became much easier to understand. So let's break it down from the beginning. What Is Docker? Docker is a platform for building, packaging, and running applications in isolated environments called containers . The basic idea is simple: Package an application together with the things it needs to run, and make that package portable. For example, imagine you build a Python application. Your application might depend on: Python 3.12 FastAPI Uvicorn Several Python packages Environment variables Certain system libraries On your computer, everything works. Then someone else downloads your project. They install a different Python version. A package is missing. Something behaves differently. Now you have: "It works on my machine." Docker helps reduce this problem by allowing you to define the environment your application should run in. The Four Concepts You Need to Understand Before learning Docker commands, understand these four things: Docker Image ↓ Docker Container ↓ Ports ↓ Volumes Let's look at each one. 1. What Is a Docker Image? A Docker image is a packaged, read-only template used to create containers. Think of it like a blueprint. For example: Docker Image │ ├── Ubuntu ├── Python ├── Application code ├── Dependencies └── Configuration An image contains the instructions and filesystem needed to create a container. You can download images from container registries such as Docker Hub. For example: docker pull nginx This downloads the Nginx image. You can see your downloaded images with: docker images You might see s
AI 资讯
2.Self-Hosted AI: n8n + Ollama, local AI workflows on your Mac
If you want AI agents running on your own machine, with your own models, and no data leaving your computer, this is the article :). This is part three of the series. In part one we set up PostgreSQL, and in part two we covered the LLM concepts (models, parameter, quantization, context, capabilities, VRAM). Today we put them to work: n8n for the workflows and Ollama for the models. One prerequisite: Docker. If you do not have it yet, install Docker Desktop for Mac following the official guide [ Docker docs ]. Quick setup: n8n The fastest path is n8n's official Self-hosted AI Starter Kit, a Docker Compose template that ships n8n, Ollama, Qdrant (a vector store) and PostgreSQL preconfigured to talk to each other [ n8n docs ]. git clone https://github.com/n8n-io/self-hosted-ai-starter-kit.git cd self-hosted-ai-starter-kit cp .env.example .env # file where your passwords are stored The .env file is hidden by default. In Finder, press Command + Shift + Period to show hidden files, or just edit it from the terminal. Update the credentials, for example: POSTGRES_USER = admin POSTGRES_PASSWORD = root POSTGRES_DB = n8n Also replace the N8N_ENCRYPTION_KEY and N8N_USER_MANAGEMENT_JWT_SECRET values with your own random strings. Now one Mac-specific detail. Docker on Apple Silicon cannot use the Mac's GPU, so the kit's README recommends running Ollama natively on your Mac for speed and letting the containers connect to it [ starter kit README ]. That is what we'll do. Set this in your .env : OLLAMA_HOST = host.docker.internal:11434 Then start everything: docker compose up Open http://localhost:5678 to create your n8n account (once), and http://localhost:5678/home/workflows is where your workflows and agents live. If you only want n8n without the rest of the kit, this single command works too [ n8n docs ]: docker run -it --rm --name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n docker.n8n.io/n8nio/n8n Quick setup: Ollama On the Mac side (from part two, condensed): brew install olla
AI 资讯
The Same Setting, Three Different Answers: Why 0.0.0.0 Isn't Always What You Want
There is a line in almost every Python web tutorial that nobody explains: uvicorn main:app --host 0.0.0.0 --port 8000 I copied it for weeks without thinking about it. Then I deployed the same application three times — to a local VM, to a production server, and into a container — and the correct value was different every time. Twice it was 0.0.0.0 . Once, in the place that mattered most, it was not. That gap is worth writing about, because the setting itself is trivial and the reasoning behind it is not. What the Flag Actually Controls A server process doesn't "open a port." It creates a socket and binds it to an address. The bind address answers one question: which network interfaces should this socket accept connections from? A machine has more than one interface: lo (loopback) — reachable only from inside the machine ( 127.0.0.1 ). Packets addressed there never reach a physical network card; the kernel loops them straight back. 0.0.0.0 — a wildcard meaning every interface this machine has , including ones added later. So the flag isn't about security or convenience. It's about reachability — and reachability depends entirely on what sits in front of the process. Case 1: The Local VM — 0.0.0.0 I was running the service inside a Multipass VM and wanted to hit it from the browser on my laptop. The laptop is outside the VM, so binding to loopback would have made the service invisible to it. curl inside the VM would work; the browser outside would get connection refused. Decision: wildcard bind. Nothing sits in front of the process, and nothing needs protecting. Case 2: Production — 127.0.0.1 Here I copied the same line at first, and it was wrong. The production box has a public IP. Binding to 0.0.0.0 there means the application is directly exposed to the internet: no TLS, no rate limiting, no authentication. Within hours of provisioning that server, its SSH logs showed hundreds of automated login attempts against usernames like admin and oracle . The same scanners try
AI 资讯
What a Malicious Ollama Model Can Actually Do to Your Host, and How to Sandbox /api/pull
A malicious Ollama model is not a virus you double click, but it is untrusted input handed to a C parser, a template engine and your filesystem in one request. The realistic damage from a hostile /api/pull is disk exhaustion, VRAM starvation, blob writes under ~/.ollama/models , a poisoned chat template that silently rewrites every prompt, and memory corruption in the GGUF loader if the file is crafted for it. None of that requires a vulnerability in your app code, only an Ollama daemon that trusts whoever can reach port 11434 and whichever registry a tag points at. Bind the daemon to localhost, pin models by SHA256 digest, run the container as a non root user with a read only root filesystem and a capped model volume, and the entire class collapses to a bad model that answers badly. TL;DR by reader profile: Solo developer running Ollama on a laptop, for example a contractor testing llama3.1:8b locally: leave OLLAMA_HOST at 127.0.0.1:11434 and pin digests, because your only real exposure is pulling a model whose tag moved under you. Two person startup running Ollama on one rented GPU box, for example a founder pair serving an internal assistant: run it in Docker as UID 1000 with --read-only , --cap-drop ALL and a sized model volume, because a single unbounded pull can fill the disk that also holds your Postgres data. Team fronting Ollama with Open WebUI or Continue, for example five engineers sharing one workstation: put model management behind the proxy and block /api/pull , /api/create , /api/push and /api/delete for normal users, because chat access and registry access are not the same privilege. Anyone building agents or RAG on Ollama, for example a support bot with tool calling: treat the Modelfile TEMPLATE and SYSTEM blocks as attacker controlled text, because a poisoned template reaches the model before your prompt does. Consultancies holding client data, for example a two person shop under an NDA: keep model pulls on a staging host, mirror approved blobs int
AI 资讯
Directus + Coolify: Should You Decouple Postgres & Redis?
This is Part 2 of the Directus + Coolify series. If you're new here, start with "Secure Your VPS Before Hackers Do" and the first Directus + Coolify post — the bundled, single-Compose-file setup — before following along with this one. Introduction In the first method, we coupled all of the services into one stack using a single Docker Compose file. The network between all services was created automatically, and we didn't have to start them up individually — which removes the risk of a race condition if service startup isn't handled properly. If you're running a single app, that's genuinely the recommended way to set up Directus on a Coolify-managed VPS. Going in, I assumed there were several good reasons to split the services apart instead — more control over backups, monitoring, restarts, that kind of thing. So before recommending decoupling, I actually tested each of those assumptions on a live Coolify instance. Most of them turned out to be wrong. Myth 1: Restarting Directus Restarts the Whole Stack I expected that restarting Directus inside the bundled Compose file would restart Redis and Postgres along with it. It doesn't. Coolify lets you restart each service in the stack independently — Directus, Database, and Cache each get their own Restart button, right there in the same view. No decoupling needed for this one. Myth 2: You Need a Separate Database Resource for S3 Backups Same story. Even with Postgres bundled inside the Directus Compose file, Coolify still gives it its own dedicated Backups option, S3 included. This isn't a separate-resource-only feature. Myth 3: Scheduled Tasks Require Separate Services Also not true. Coolify exposes a Scheduled Tasks tab per service, even inside a single bundled stack — complete with a Container name dropdown letting you target the cron job at just the database, or just Directus, without splitting anything apart. What Actually Holds Up Two things survived testing. First: metrics. This one's confirmed directly in Coolify'
AI 资讯
How Much Should Live Together? Learning to Isolate Services the Hard Way
Also Published On trever.cloud Medium LinkedIn Most of us who get into self-hosting start the same way: start with linux, throw a few apps into Docker, get them running and connectable outside the home network, and call it good for months, maybe even years. Nothing wrong with that approach. A compose file and a spare mini PC gets you further than you think, and if it works and you don't have to think about it, that's a perfectly fine place to stop. Then there's the rest of us. The people who get that first setup running, feel the little spark of "wait, I built this", and immediately start wondering what else is possible. More services. Less babysitting. A real answer to "what happens if this box dies at 2am". If any of that sounds familiar, this one's for you. If you keep going, you'll eventually run into the question every self-hosted setup faces sooner or later, whether you notice it happening or not, "how much should live together, and how much should be kept apart?". Put everything on one box and you quickly feel the fragility when one bad update takes everything down with it. Or when nightly backups put services on hold longer and longer. Split everything into its own isolated piece and you've gained resiliency but now manage a lot of moving parts. Most of the actual learning in running infrastructure happens in the space between those two answers. Where you draw that line is where most of the real infrastructure lessons live. Over the years, I've lived through a few different answers to that question in my own homelab, and each one taught me something the previous one couldn't. It started with a large VM, Docker installed, and every service I wanted to self-host running as a container inside. It was the fastest path to "it's actually working", and at the time that was the whole goal. I didn't know yet what I'd eventually want out of this thing, so keeping the infrastructure simple while I figured that out made sense. That setup carried me a long way, and I don
开发者
Halfway Through the MLH Production Engineering Fellowship
I'm halfway through the MLH Production Engineering Fellowship, and while I've learned a lot technically—from Linux fundamentals, Docker, NGINX, automated testing, and contributing to open source, the thing that has stood out to me most is how well the program is structured. Beyond the technical curriculum, there is a strong emphasis on interview preparation and career growth. We’ve had regular opportunities to practice technical interviews, receive feedback, and stay in close contact with our Meta mentors, who have been incredibly approachable throughout the program. Looking forward to seeing what the second half of the fellowship has in store. Thanks to the MLH team, mentors, and my podmates for making it such a rewarding experience so far!
AI 资讯
Deploying code-server for VS Code on Ubuntu 24.04
code-server is the open-source project that runs full VS Code including extensions, integrated terminal, Git, IntelliSense — on a remote server, accessible from any browser. This guide deploys it on Ubuntu 24.04 with Docker Compose, fronted by Traefik for automatic HTTPS. Prerequisites: an Ubuntu 24.04 server (1GB RAM / 2 vCPU minimum), a domain A record (e.g. code.example.com ), Docker and Docker Compose installed. Set Up the Project $ mkdir -p ~/vscode-server/ { project,config,local,letsencrypt } $ cd ~/vscode-server project — your editable workspace config — code-server settings/extensions local — user-specific data letsencrypt — Traefik's ACME certificate storage Find your UID/GID and add yourself to the docker group: $ id $USER $ sudo usermod -aG docker $USER Write the Compose File $ nano docker-compose.yml services : code-server : image : codercom/code-server:latest container_name : code-server user : " UID:GID" # Replace with your user's UID and GID environment : - PASSWORD=SECURE_PASSWORD # Replace with a strong password - DOCKER_USER=LINUXUSER # Replace with your username volumes : - ./project:/home/coder/project - ./config:/home/coder/.config - ./local:/home/coder/.local networks : - internal restart : unless-stopped labels : - " traefik.enable=true" - " traefik.http.routers.code-server.rule=Host(`CODE.EXAMPLE.COM`)" # Replace with your domain name - " traefik.http.routers.code-server.entrypoints=websecure" - " traefik.http.routers.code-server.tls.certresolver=myresolver" - " traefik.http.services.code-server.loadbalancer.server.port=8080" traefik : image : traefik:latest container_name : traefik ports : - " 80:80" - " 443:443" volumes : - /var/run/docker.sock:/var/run/docker.sock:ro - ./letsencrypt:/letsencrypt command : - " --providers.docker=true" - " --providers.docker.exposedbydefault=false" - " --providers.docker.network=internal" - " --entrypoints.web.address=:80" - " --entrypoints.websecure.address=:443" - " --entrypoints.web.http.redirections.entr
AI 资讯
Installing Ghost Blogging Platform on Ubuntu 24.04
Ghost is an open-source publishing platform with built-in newsletters, memberships, subscriptions, ActivityPub federation, and Tinybird-powered web analytics. This guide covers two install paths on Ubuntu 24.04: Ghost-CLI for a traditional host install, and Docker Compose for a containerized deployment with analytics. Prerequisites: an Ubuntu 24.04 server, non-root sudo user, a domain A record (e.g. ghost.example.com ). Option A: Install with Ghost-CLI Install Node.js Ghost requires Node v22 LTS — check compatible versions before installing elsewhere. $ curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh $ sudo -E bash nodesource_setup.sh $ sudo apt install -y nodejs $ node -v Install and Configure MySQL $ sudo apt install -y mysql-server $ mysql --version $ sudo mysql_secure_installation Walk through the prompts: enable password validation ( y ), pick strong policy ( 2 ), remove anonymous users ( y ), restrict root to localhost ( y ), drop the test database ( y ), reload privileges ( y ). $ sudo mysql mysql > CREATE DATABASE ghost_db ; mysql > CREATE USER 'ghostuser' @ 'localhost' IDENTIFIED BY 'Your_password2!' ; mysql > GRANT ALL PRIVILEGES ON ghost_db . * TO 'ghostuser' @ 'localhost' ; mysql > FLUSH PRIVILEGES ; mysql > EXIT ; Install Nginx $ sudo apt install -y nginx $ sudo ufw allow 'Nginx Full' $ sudo systemctl status nginx Install Ghost $ sudo npm install ghost-cli@latest -g $ sudo mkdir -p /var/www/html/ghost $ sudo chown $USER : $USER /var/www/html/ghost $ sudo chmod 775 /var/www/html/ghost $ cd /var/www/html/ghost $ ghost install The installer prompts for: Blog URL : https://ghost.example.com MySQL hostname : localhost MySQL username/password/database : from the setup above Set up Nginx? : y Set up SSL? : y (installs acme.sh ) Email for SSL : your address Set up Systemd? : y Start Ghost? : y Manage the Config $ nano /var/www/html/ghost/config.production.json $ cd /var/www/html/ghost $ ghost restart Or via systemd (replace ghost-example
AI 资讯
Gubernator Weekly Update: CoreDNS Aqueducts, SRE Stack, Network Topology & Cluster Auto-Updates!
Gubernator Weekly Update: CoreDNS Aqueducts, SRE Stack, Network Topology & Cluster Auto-Updates! Gubernator Weekly Update Banner Review Gubernator Weekly Update Banner What an intense week for Gubernator (gbnt)! If you're new here, Gubernator is the "Goldilocks" container orchestrator that bridges the gap between Docker Swarm's simplicity (native Compose support, simple node joining) and Nomad's scheduling flexibility (hardware targeting, labels, task-based management). Over the past 7 days, Gubernator evolved from a single-node engine into a production-ready cluster ecosystem. Here is a breakdown of everything shipped this week! 1. Ingress & Service Discovery ("The Aqueducts") One of our biggest milestones this week was shipping automated internal DNS resolution and edge ingress routing: CoreDNS Integration: Every node running Gubernator can now deploy CoreDNS. Containers across all hosts can resolve internal service IPs using dynamic domain names (.gbnt.test). As containers spin up or die, Gubernator's manager updates CoreDNS records in real-time. Caddy Ingress: Exposing web services is now effortless. Services deployed with routing labels are automatically proxied by Caddy, managing SSL and HTTP/HTTPS ingress dynamically. 2. SRE Observability Suite (gbnt monitor init) Observability shouldn't require writing 500 lines of YAML. With a single command, gbnt monitor init, Gubernator deploys a complete, production-grade observability stack: Prometheus & cAdvisor: Detailed container and host-level metrics collection (CPU, RAM, Network I/O). Loki & Promtail: Centralized log aggregation across all containers. Grafana: Pre-configured dashboards for instant visualization out of the box. Jaeger Tracing: Full OpenTelemetry distributed tracing support (OTLP gRPC :4317 & HTTP :4318). Interactive Network Topology (Weave Scope Integration) Understanding how containers talk to each other across a distributed cluster can be tough. We integrated Weave Scope directly into the Flutter
AI 资讯
The Alpine Mirage: How Upgrading Python Broke My Build and Led to a Truer Security Posture
This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry . The Initial Goal: "Upgrade and Secure" Like many developers, I recently fell into the trap of assuming that "smaller is always better, and newer is always safer." I decided to upgrade my terminal-based web UI project, py_terminal , to the bleeding-edge python:3.15-rc-alpine Docker base image. The logic was sound: Alpine Linux has a much smaller footprint, meaning a smaller attack surface. Python 3.15 Release Candidate would give me early access to performance improvements and patches. What followed was a cascading series of build failures that taught me a valuable lesson about container architecture, Python's C-API, and what actually makes a container secure. The Descent into Dependency Hell The moment I pushed the Dockerfile update and ran docker build , the pipeline exploded. 1. The Missing Wheels The first error was abrupt: ERROR: No matching distribution found for litellm==1.93.0 Because I was combining a release candidate of Python (3.15-rc) with Alpine (which uses musl libc instead of the standard glibc ), pre-compiled binaries (wheels) simply didn't exist for several of my packages. pip was forced to download raw source code and build from scratch. 2. The Rust Compiler (Wait, Rust?) One of litellm 's underlying dependencies is fastuuid , which is written in Rust. Because pip was building from source, it attempted to download the Rust toolchain ( cargo ). It immediately failed: Error loading shared library libgcc_s.so.1: No such file or directory Because Alpine is so incredibly stripped down, it didn't even have the basic C runtime library ( libgcc ) required to run the Rust compiler. 3. Fighting the PyO3 API Determined to win, I added the heavy build tools to Alpine ( apk add build-base cargo libffi-dev ). The build got further, but then crashed while compiling tiktoken and pydantic-core . The bridge between Rust and Python is handled by a library called PyO3 . It explicitly re
AI 资讯
Building an On-Premise Kubernetes Cluster — Part 6: Deploying, Updating, and Scaling Your Own Application
🇧🇷 Leia a versão em português aqui In Part 5 of this series, we validated the cluster end to end by deploying Nginx. Now let's go one step further: build a custom application's Docker image, publish it, get it running in the cluster, and explore day-to-day operations — version updates, rollback, and scalability (both manual and automatic). As an example, we used a simple REST API ( myapp.war ), built with Spring Boot, purely for illustration — the process applies to any application packaged as a container image. Building the application's Docker image The first step is writing the application's Dockerfile . In this example, a lightweight base image ( alpine ) was used, with Java 11 installed to run the application: FROM alpine WORKDIR /opt/app RUN apk update && apk add vim openjdk11-jre COPY runapp.sh . CMD ash runapp.sh Building the image docker image build -t oregontecnologia/myapp-api:1.0.0 . Publishing the image Before using the image in the cluster, it needs to be available in some registry — either Docker Hub or a private registry . If you'd rather host your own on-premise registry (recommended for corporate environments or those without internet access), check out the companion article on creating a local registry server . To publish to Docker Hub: docker login username: password: docker push oregontecnologia/myapp-api:1.0.0 Deploying the application With the image published, you can check the cluster's current state before proceeding: kubectl get pods -o wide kubectl get deploy -o wide Create the Deployment directly from the command line, pointing to the published image: kubectl create deploy myapp-deploy --image = oregontecnologia/myapp-api:1.0.0 Unlike previous examples in this series (where we used YAML files with kubectl apply -f ), here the Deployment is created directly via the command line with kubectl create deploy . Both approaches are valid — YAML files are more suitable when you need to version and consistently reapply configurations. Exposing the
AI 资讯
How to safely run AI-generated code — a practical sandboxing checklist
Cross-post. Original: stellarbytecapital.com/blog/how-to-run-ai-generated-code-safely If you're building an AI agent, sooner or later it will write code and you'll have to run that code. The moment you do, you're executing something no human reviewed against your infrastructure. This is a practical checklist for doing that safely — the controls we use in production, in the order they matter. The short version: treat every piece of AI-generated code as hostile, and design so that even a full compromise of the runtime buys the attacker nothing. First, the threat model Before controls, be honest about what can go wrong when you run untrusted code: It reads or exfiltrates data belonging to other users on the same host. It reaches out to the network to leak data or pull a payload. It leaves state behind — temp files, mutated env, background threads — that corrupts the next run. It exhausts CPU, memory, or disk and takes down the shared service. It escapes the sandbox entirely via a kernel or runtime bug. "The model probably won't do that" is not a control. Design for the case where it does. The core pattern: one disposable sandbox per execution The single highest-leverage decision: run every execution in its own fresh sandbox, and destroy it after the run. Never reuse. Reuse is where most bugs and attacks live — leaked file descriptors, leftover temp files, mutated globals, a background thread from the last run. If nothing is ever reused, that entire class of problems disappears. To keep it fast, keep a warm pool of ready sandboxes and backfill each one as it's consumed. The checklist Isolation boundary — use a real boundary, not a language-level "safe eval." A container is the baseline; a microVM ( gVisor , Firecracker ) is stronger against kernel escapes. Network egress: default-deny — no outbound network by default. An escaped agent that can't reach the internet has nowhere to send data. Filesystem: read-only + ephemeral — mount inputs read-only; give a scratch space
AI 资讯
Deploying to AWS Lightsail with a Docker image from ECR
Lightsail is a good home for a single small container: flat pricing, bandwidth included, and none of the VPC/security-group ceremony of EC2. The one rough edge is pulling a private image from Amazon ECR , because a standard Lightsail instance can't authenticate to ECR the way EC2 can. This post walks the whole path. The pipeline we're building: docker build ──push──> ECR (private repo) ──pull──> Lightsail instance ──run──> container What you'll need An AWS account and the AWS CLI installed locally. Docker installed locally (to build) and on the Lightsail box (to run). A Dockerfile that produces a runnable image. If you're deploying a Next.js app, a standalone output image works well. 1. Create the ECR repository ECR is a private Docker registry. Create one repository per image: aws ecr create-repository \ --repository-name project-name \ --region us-east-1 Note the repositoryUri in the output — it looks like: <account-id>.dkr.ecr.us-east-1.amazonaws.com/project-name You'll use that URI everywhere below. Export it to save typing: export ECR_URI = <account-id>.dkr.ecr.us-east-1.amazonaws.com/project-name export AWS_REGION = us-east-1 2. Build the image locally First, the Dockerfile . This is a multi-stage build for a Next.js app using output: "standalone" — the first stage installs dependencies and builds, the second copies only the traced runtime files into a slim image that runs as a non-root user: FROM node:24-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:24-alpine WORKDIR /app ENV NODE_ENV=production ENV PORT=3000 ENV HOSTNAME=0.0.0.0 # Standalone output ships only the traced files needed to run the server. # public and .next/static are not included by default and must be copied in. # --chown makes the files writable by the non-root user so Next.js can write # its runtime cache to /app/.next/cache. COPY --from=builder --chown=node:node /app/public ./public COPY --from=builder --chown=node:node /app/.next/stand
AI 资讯
Run Kubernetes in Docker on Ubuntu for Local Development
There's a delightfully literal answer to "Kubernetes with Docker": kind — Kubernetes IN Docker. Each node is a Docker container running a full Kubernetes node image. On an Ubuntu workstation it gives you a real, throwaway, multi-node cluster in about 30 seconds. It's my default for local dev and for CI. Prerequisites on Ubuntu You need Docker Engine and kubectl . If you don't have Docker yet: sudo apt-get update && sudo apt-get install -y docker.io sudo usermod -aG docker $USER && newgrp docker # run docker without sudo Install kind (single static binary): curl -fsSLo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind kind version A one-command cluster kind create cluster --name dev kubectl cluster-info --context kind-dev docker ps # you'll see a dev-control-plane container — that's your node kind wrote a kubeconfig context for you. Tear the whole thing down just as fast: kind delete cluster --name dev A realistic multi-node cluster Most bugs only show up with more than one node (scheduling, affinity, PodDisruptionBudgets). Define it in a config file: # kind-cluster.yaml kind : Cluster apiVersion : kind.x-k8s.io/v1alpha4 nodes : - role : control-plane kubeadmConfigPatches : - | kind: InitConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings : - containerPort : 80 hostPort : 8080 protocol : TCP - role : worker - role : worker kind create cluster --name dev --config kind-cluster.yaml kubectl get nodes The extraPortMappings bit is the trick people miss: it forwards a port from your Ubuntu host into the control-plane container, so an ingress controller inside the cluster is reachable at http://localhost:8080 . Loading a locally-built image (no registry needed) This is kind 's best feature for the Docker workflow. Build with Docker, push straight into the cluster's nodes — no registry round-trip: docker build -t myapp:dev . kind load docker-image myapp:dev --name
AI 资讯
minikube with the Docker Driver on Ubuntu: A Practical Local Cluster
minikube is the other "Kubernetes in Docker" option on Ubuntu, and with --driver=docker it runs the cluster inside a Docker container just like kind — but ships with addons (ingress, metrics-server, dashboard, a built-in registry) that make it feel more like a real cluster. Here's a practical setup and how it differs from kind . Install on Ubuntu You need Docker first ( sudo apt-get install -y docker.io , then add yourself to the docker group). Then: curl -fsSLo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube /usr/local/bin/minikube minikube version Start with the Docker driver minikube start --driver = docker # make it the default so you don't repeat the flag: minikube config set driver docker kubectl get nodes docker ps # a 'minikube' container is your node Size it for real work: minikube start --driver = docker --cpus = 4 --memory = 8g --disk-size = 40g The addons are the reason to pick minikube minikube addons list minikube addons enable ingress minikube addons enable metrics-server minikube dashboard # opens the web UI ingress gives you a working NGINX ingress controller with no manifest wrangling — genuinely useful when you want to test ingress routing locally. The Docker image workflow minikube runs its own Docker daemon inside the node container. The neat trick is pointing your shell's Docker CLI at that daemon, so images you build are immediately visible to the cluster with no push: eval $( minikube docker-env ) # your `docker` now talks to minikube's daemon docker build -t myapp:dev . kubectl create deployment myapp --image = myapp:dev # remember: imagePullPolicy: IfNotPresent so it doesn't try a registry pull Undo it when you're done so docker points back at your host daemon: eval $( minikube docker-env -u ) There's also a built-in registry if you prefer the push model: minikube addons enable registry Accessing services from Ubuntu Two common patterns: # quick tunnel to a single service (prints a
AI 资讯
I Built a Manga Reader That Works on Every Platform --Here's How
I Built a Manga Reader That Works on Every Platform — Here's How Nyora is a free, open-source manga/manhwa/manhua reader for Android, iOS, macOS, Windows, Linux, Web, and even Docker — with AI-powered on-device translation and cross-platform sync. The Problem Every manga reader makes you choose: Free but ad-riddled (most Android readers) Polished but paywalled (commercial apps) Powerful but single-platform (Tachiyomi, Aidoku) I wanted one library — same titles, same progress, same bookmarks — on my phone, laptop, and browser. No ads. No account required. So I built it. What Nyora Does Every Platform, One App Platform Distribution Android APK (sideload) iOS/iPadOS IPA via AltStore/SideStore macOS .dmg or brew install --cask nyora Windows .exe (x64 + ARM64) Linux .deb , .rpm , or curl installer Web web.nyora.xyz — zero install Docker Single container, self-hosted No account needed to read. Cloud sync is opt-in. AI Translation That Understands Manga This is the flagship feature. Instead of dumping translated text over the artwork: Detects text baked into speech bubbles and captions Translates using on-device ML Typesets the result back over the original artwork Each platform uses the best local engine: Android : Google ML Kit + ONNX Runtime iOS : Apple Intelligence + Google Translate macOS : Apple Vision + MangaOCR CoreML Windows : Windows OCR Linux : Tesseract There's also an Ensemble AI Narrative Engine that tracks character names and speaking styles across chapters so translations stay consistent. 1,100+ Sources The Android app pulls from 1,100+ manga sources via 35 generic engine templates (Madara, FoolSlide, MMRCMS, etc.). Web has ~390 live, health-checked sources. Desktop ports are growing toward parity. Free Cloud Sync Sync library, categories, reading history, bookmarks, and exact page progress across all six platforms. Two sign-in methods: Google OAuth Nyora Cloud (email + password, free) Self-hostable — the backend is just Supabase/PostgreSQL with row-level s