今日已更新 264 条资讯 | 累计 23847 条内容
关于我们

标签:#docker

找到 73 篇相关文章

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

2026-07-24 原文 →
AI 资讯

GitLab CI "Cannot connect to unix:///var/run/docker.sock"

The fast fix If your GitLab CI job fails with Cannot connect to the Docker daemon at unix:///var/run/docker.sock , your docker client is looking for a local socket that does not exist inside the job container, because DOCKER_HOST is not set. Point the client at the docker:dind service over TCP and the error goes away: build : image : docker:28.3 services : - name : docker:28.3-dind alias : docker variables : DOCKER_HOST : tcp://docker:2376 DOCKER_TLS_CERTDIR : " /certs" DOCKER_CERT_PATH : " /certs/client" DOCKER_TLS_VERIFY : " 1" script : - docker info - docker build -t my-app . That is the whole fix for the common case. The rest of this page explains why the socket variant of the error is different from the tcp://docker:2375 variant, and covers the two other setups (socket-mounted runners and the Kubernetes executor) where the same message shows up for a different reason. Why you get the unix socket variant specifically This error is not the same as Cannot connect to the Docker daemon at tcp://docker:2375 . The address in the message tells you exactly what the client tried: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? When DOCKER_HOST is empty, the Docker CLI falls back to its compiled-in default, the local unix socket at /var/run/docker.sock . Inside a GitLab CI job that uses the docker executor, that socket file simply is not there. The daemon runs in a separate docker:dind service container, not in your job container, so there is nothing listening on the local socket. The client connects, finds no socket, and prints the message above. The tcp://docker:2375 form is the opposite problem: DOCKER_HOST is set correctly but the dind service is not reachable (missing service, no privileged mode, or a TLS mismatch). If you are seeing that address instead, read the companion write-up on the tcp://docker:2375 form of this error , which walks the service and privileged-mode causes in detail. This page is about the case w

2026-07-23 原文 →
开发者

Coolify: The Complete Manual Setup Guide (For When the Auto-Install Script Won't Cut It)

Coolify's one-line install script is great — until it isn't. Right now it officially supports Ubuntu 20.04, 22.04, and 24.04 LTS. If you're running anything newer (Ubuntu's already on 26.04 LTS), the script won't work and you're left doing it manually. This is that manual walkthrough — set up in the order that fits a security-first VPS workflow rather than the order Coolify's own docs use. If you've been following along with the Ansible playbooks from earlier in this series, this picks up right where that left off. Minimum Hardware Requirements CPU: 2 cores Memory: 2 GB RAM Storage: 30 GB free Coolify can technically run below this, but it's not recommended. Prerequisites Before touching Coolify itself, you'll need: SSH access to your VPS CURL installed Docker Engine installed If you're reconnecting to a server you've rebuilt or re-provisioned, clear the old fingerprint first: ssh-keygen -f '/home/your-path/.ssh/known_hosts' -R 'your-vps-ip' Installing SSH If you followed the earlier videos in this series, OpenSSH is already installed. If not: sudo apt update && sudo apt install -y openssh-server Confirm it's running and check which port it's listening on (you should have already changed this from the default 22 — see the VPS security video): sudo systemctl status ssh sudo ss -tulpn | grep ssh Installing CURL sudo apt update && sudo apt install -y curl curl --version curl and ca-certificates also get installed as part of the apt-update Ansible playbook below, so this may already be handled. Running the First Ansible Playbook Connect Ansible to the VPS: ANSIBLE_HOST_KEY_CHECKING = FALSE ansible -i ./inventory/hosts vpsDemo -m ping --user root --ask-pass Then run the update playbook: ansible-playbook ./playbooks/apt-update.yml --user root -e "ansible_port=22" --ask-pass --ask-become-pass -i ./inventory/hosts If you haven't set up the Ansible inventory and playbooks from the earlier videos, do that first — this guide assumes they're already in place. Installing Docker

2026-07-23 原文 →
AI 资讯

From Docker Build to Kubernetes Deploy on Ubuntu: The Image Workflow That Never Changed

Amid all the noise about dockershim, one thing got lost: the everyday workflow of building an image with Docker and running it on Kubernetes never changed. Docker is still an excellent build tool, Kubernetes still runs OCI images, and on Ubuntu the loop is clean. Here it is end to end. 1. A build-friendly Dockerfile Multi-stage keeps the runtime image small and the attack surface low — this matters more on Kubernetes, where you pull the image onto every node that schedules the pod: # build stage FROM golang:1.22 AS build WORKDIR /src COPY go.* ./ RUN go mod download COPY . . RUN CGO_ENABLED = 0 go build -o /out/api ./cmd/api # runtime stage — distroless, no shell, tiny FROM gcr.io/distroless/static:nonroot COPY --from=build /out/api /api USER nonroot:nonroot EXPOSE 8080 ENTRYPOINT ["/api"] 2. Build and push with Docker on Ubuntu Use buildx (bundled with modern Docker) so you can build multi-arch — worth it if any nodes are arm64: docker buildx build \ --platform linux/amd64,linux/arm64 \ -t registry.example.com/api:1.4.2 \ --push . Tag with an immutable version, never rely on :latest . Kubernetes caches images per node; :latest makes "which build is actually running?" unanswerable and breaks rollbacks. 3. A deployment that behaves in production apiVersion : apps/v1 kind : Deployment metadata : name : api spec : replicas : 3 selector : { matchLabels : { app : api } } template : metadata : { labels : { app : api } } spec : containers : - name : api image : registry.example.com/api:1.4.2 # the exact tag you pushed imagePullPolicy : IfNotPresent ports : [{ containerPort : 8080 }] resources : requests : { cpu : " 100m" , memory : " 128Mi" } limits : { memory : " 256Mi" } readinessProbe : httpGet : { path : /healthz , port : 8080 } initialDelaySeconds : 3 livenessProbe : httpGet : { path : /healthz , port : 8080 } initialDelaySeconds : 10 The readinessProbe is the piece people skip and regret: without it, Kubernetes sends traffic to a pod before your app is listening, and

2026-07-23 原文 →
AI 资讯

Install Docker on Ubuntu 26.04 (the right way, with the docker-group truth)

The wrong way to install Docker on Ubuntu is the one that looks easiest: sudo apt install docker.io . That package exists, it installs, and it runs a container. It is also whatever version happened to be frozen into the archive when 26.04 was cut, it lags the real releases by months, and it ships without the Compose and Buildx plugins you will want by the end of the week. Use Docker's own apt repository instead, and this is the post I keep open so I do not re-derive the repo setup from memory each time. This is short on purpose. The steps are the official ones, and the only place worth slowing down is step 5, where adding yourself to the docker group quietly hands out root. That tradeoff is the part most guides skip, and it is the one thing here actually worth reading twice. TL;DR Remove any distro docker.io / containerd packages, add Docker's GPG key and the deb822 .sources repo, then sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin . Verify with sudo docker run hello-world . Add yourself to the docker group to drop the sudo (it is root-equivalent, more below). Prerequisites Ubuntu 26.04 (Resolute Raccoon), server or desktop, on amd64 or arm64 . A user with sudo. If you are still on root, create a sudo user first . Outbound HTTPS to download.docker.com . 1. Remove the distro Docker packages first Ubuntu ships its own docker.io , docker-compose , and containerd packages, and any of them will fight the official ones over the same files and the same containerd socket. Clear them out before you add Docker's repo. This is safe on a fresh box because there is nothing to lose yet; on a box that already ran the distro Docker, it removes the packages but leaves your images and volumes in /var/lib/docker alone. sudo apt remove $( dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1 ) The dpkg --get-selections wrapper is just so the command does not error out on pac

2026-07-23 原文 →
AI 资讯

Defeating the Fargate Cold Start Chaos with SOCI

If you've ever hit deploy on AWS Fargate and watched the task sit in PENDING forever, this one's for you. I ran a small experiment with Seekable OCI (SOCI) the AWS thing that promises to fix Fargate cold starts. This article is what I learned. The good, the boring, and the "wait, that didn't work?" bits. You'll walk away knowing what SOCI is, whether you should bother setting it up, and what real numbers look like! Prerequisites ✅ You've deployed something on AWS Fargate before. You know what a Docker image is. You have an AWS account you're OK spending ~$5 on. That's it. 🤔 The Problem Fargate is great. Push a container, get a running task. No nodes to manage! Until you use a big image. Every Fargate task pulls the whole image before starting. No shared cache. No head start. If your image is 3 GB, your task waits for 3 GB to download. Every time. Every task. For an ML model or a heavy Java service, cold start becomes minutes, not seconds. Two stats made me actually care about this: 76% of container startup time is just downloading the image. Only 6.4% of that image data is needed to actually start the app. So you're pulling 100% to use 6.4%. And it costs you 76% of your startup budget doing it. That's ridiculous!! This isn't a Fargate-only problem, by the way. It's a container problem. But Fargate hurts more because you can't cache anything at the host level. I presented this talk at AWS Community Days Bangalore 2026 💡 What is SOCI? SOCI stands for Seekable OCI . Simple idea: Instead of downloading the whole image before starting the container, download only the parts the app needs right now. Everything else gets pulled lazily, in the background, while the app is already running. The way it works: You push your image to ECR like normal. A separate tool builds an index a byte-level map of what's in each layer. Fargate reads the index at startup and only fetches the bytes it actually needs to boot the process. As the app tries to read more files, Fargate fetches those

2026-07-22 原文 →
AI 资讯

Late Night Shipping Safi Budget Engine Updates & Render Deployment published

Finished up a solid coding sprint tonight working on Safi-Budget a financial management application built around the 50/30/20 budget framework. I'm currently building and training over at Zone01Kisumu , and getting this build updated and deployed live was the main goal for today's session. What Was Updated Today Localized Currency Logic: Updated the core engine defaults from EUR over to** KES** (Kenyan Shillings) to better support local financial tracking workflows. Auth Flow Refinements:** Ironed out session management and routing logic to ensure clean sign-in and logout behavior across the app. Containerization & Deployment:** Confirmed the Go backend containerizes smoothly with Docker and runs cleanly on Render. Tech Stack Language: Go (Golang) Containerization: Docker Deployment Platform: Render Live Demo & Link You can test out the live deployment here: 👉 Safi Budget Engine Live App

2026-07-22 原文 →
AI 资讯

Running PostgreSQL with Docker

Installing Postgres directly on your machine works, but it gets messy fast once you're juggling multiple projects that each want different versions, extensions, or seed data. Docker sidesteps all of that you get a clean, disposable Postgres instance per project, and your host machine stays untouched. This guide covers running Postgres in Docker for local development: quick one-off containers, docker-compose for anything you'll come back to, persistent data, and a few things that trip people up. 1. The quickest way to get a Postgres instance running docker run --name my-postgres \ -e POSTGRES_PASSWORD = secret \ -e POSTGRES_USER = devuser \ -e POSTGRES_DB = myapp \ -p 5432:5432 \ -d postgres:16 Breaking that down: --name my-postgres — a friendly name so you can reference the container later instead of a random hash POSTGRES_PASSWORD — required; the container won't start without it POSTGRES_USER / POSTGRES_DB — optional; default to postgres if omitted -p 5432:5432 — maps container port 5432 to host port 5432 -d — detached, runs in the background postgres:16 — pin a version; avoid latest since it can silently jump major versions later Check it's running: docker ps Connect with psql (if installed locally) or from inside the container: docker exec -it my-postgres psql -U devuser -d myapp 2. Using docker-compose for anything persistent For a real project, docker-compose.yml is the better default , it's version-controlled, reproducible, and easy to extend with more services later (Redis, pgAdmin, your app itself). services : db : image : postgres:16 container_name : myapp-postgres restart : unless-stopped environment : POSTGRES_USER : devuser POSTGRES_PASSWORD : secret POSTGRES_DB : myapp ports : - " 5432:5432" volumes : - pgdata:/var/lib/postgresql/data volumes : pgdata : Start it: docker compose up -d Stop it (keeps data): docker compose down Stop and wipe data: docker compose down -v 3. Why the volume matters Without a named volume, all data lives inside the container's

2026-07-22 原文 →
AI 资讯

Building a Fully Automated SaaS: Payment to Deployment in 90 Seconds

Zero-Touch Customer Onboarding My AI agent hosting service has exactly zero manual steps between payment and deployment. Here is how: The Pipeline Customer pays via PayPal subscription Webhook fires to our server within seconds Python script validates the webhook signature Docker container spins up with Hermes Agent pre-installed API key generated via New-API Email sent to customer with credentials Customer logs in and starts using their agent Total time: ~90 seconds . No human touches anything. The Code Architecture PayPal Webhooks → Python Flask endpoint Docker API → Container creation with resource limits New-API → Token generation and quota management Gmail SMTP → Automated email delivery Caddy → Automatic HTTPS and routing Key Design Decisions Docker over VMs : Containers are faster (90s vs 5min) and cheaper. Each customer gets 0.5 CPU and 256MB RAM. New-API over custom billing : Battle-tested token management instead of rolling my own. AI over human support : The support agent is also AI. No humans in the loop at all. What Could Break PayPal webhook failures → Implement retry logic Docker daemon issues → Health checks and auto-restart Email deliverability → Fallback to backup SMTP The Result A customer can discover the site, pay, and have a working AI agent before their coffee gets cold. That is the power of full automation. Try it: AgentChip — $23.99/month, 100M API tokens included.

2026-07-18 原文 →
AI 资讯

How a Simple Ping Took 4 Hours: WireGuard, Docker Desktop, and the Silent Linux Kernel Drops

I have been working on building a private, secure network accessible from anywhere. The goal was to connect my mobile phone and my local development laptop using a WireGuard VPN , hosting the central gateway on a free-tier Google Cloud Platform (GCP) e2-micro instance. I wanted to access my self-hosted services, specifically my Docker-hosted Open WebUI , running on my local home Wi-Fi connected laptop, directly from my phone using mobile data. It sounded straightforward. But if you read my other from scratch journeys, you might have already guessed, it was not. The Setup My architectural plan was a simple hub-and-spoke topology: The Hub: GCP VM ( 10.66.66.1 ) with IPv4 forwarding enabled. Spoke 1 (My Phone): 10.66.66.2 Spoke 2 (My Laptop): 10.66.66.3 I wrote my server configurations, enabled IP forwarding ( net.ipv4.ip_forward=1 ), wrote the iptables rules to allow forwarding between peers, and started the interfaces. Then came the moment of truth. I tried to bring up the tunnel. Absolute silence. No packet moving from anywhere. Hurdle 1: The Classic Cloud NAT Trap (Internal vs. Public IP) Before I could even worry about routing packets between my phone and laptop, I couldn't even get them to handshake with the GCP server. Like many of us do when working inside a VM, I had run ip addr on the GCP instance to grab its IP address for my client configurations. I set up the WireGuard peers to point to this IP. Nothing connected. The Culprit: GCP (and AWS) operates on a 1:1 NAT mapping. The virtual network interface inside your VM only sees and binds to a private, internal cloud IP (e.g., 10.128.0.x ). The public IP assigned to your instance lives outside the VM at the VPC gateway level. By putting the internal IP into my client configs, my phone and laptop were trying to connect to a private address that didn't exist on their local networks. The Fix: I had to swap the internal IP in the client configurations with the GCP Ephemeral/Static External IP . Once the handshake

2026-07-17 原文 →
AI 资讯

4 self-hosting failures that return success

The failures that cost me the most in three years of self-hosting were never the ones that threw an error. An error is a gift: it tells you where to look. The expensive ones are the failures that report success while being broken . A page that returns 200 OK . A healthcheck that says the container is fine. A backup that exits cleanly. A command that prints nothing wrong. Everything green, everything lying. Here are four of them, all from the same box (a 2016 desktop, i7-6700 / 32 GB, Docker behind Caddy, reachable only over Tailscale). Each fails by handing you a success signal. Each cost me an evening the first time. The fixes are boring once you know them, the point is knowing the failure exists. Sanitized skeleton with all the config at the end. 1. A loading page that returns 200 This one I could find nothing written about, so it cost me the most. To keep the box quiet, I run the heavy services on-demand: Sablier stops idle containers and starts them on the first request. Caddy (with the Sablier plugin) gates a virtual host behind a container group, serves a "please wait, starting up" page while the group boots, then proxies through: myhost . my - tailnet . ts . net : 8081 { route { sablier http :// sablier : 10000 { group office session_duration 30 m } reverse_proxy nextcloud : 80 } } I gate my whole Nextcloud vhost, WebDAV included, this way. And here is the silent failure: if the gated group is not healthy, Sablier serves that HTML loading page for every request, and it serves it with 200 OK . A browser shows a spinner, fine. But my Obsidian vault syncs over WebDAV, and a WebDAV client asking for a directory listing got a 200 with a chunk of HTML instead of the XML it expected. Sync died with a cryptic no root multistatus found . Nextcloud itself was up and perfectly healthy the whole time. Every uptime check I had was green, because the gate in front kept answering 200 . The structural lesson: the moment you put a service on-demand behind a reverse proxy, tha

2026-07-14 原文 →
AI 资讯

From Resetting Passwords to Containerizing Java: My Pivot to DevOps

For 4 years, I lived in the world of IT Operations. My days were spent handling incident response, managing data lifecycles, and making sure systems stayed online. I learned how to troubleshoot under pressure, talk to frustrated users, and keep the business running. But I had a lingering frustration: I was always fixing other people's code. I never got to build it. And more importantly, I was fixing problems manually that I knew could be automated. So, I decided to make a massive pivot. I went back to university (VILNIUS TECH) and recently started a Java Engineering internship at Coherent Solutions. My goal isn't just to become a Java developer. My goal is to bridge the gap between Development and Operations- DevOps . In my first few weeks at Coherent, we started learning about enterprise architecture. But the moment that truly clicked for me was when I built my first Docker image for our project. In my past IT life, deploying an app was a nightmare. "It works on my machine!" was a constant joke (and a constant headache for the Ops team). Setting up environments, installing the right Java version, configuring databases—it was manual, error-prone, and boring. Then I wrote a Dockerfile . I packaged our Java application and its dependencies into a single, isolated container. Suddenly, I realized: This is how you solve the "works on my machine" problem forever. As someone who used to be the guy manually fixing those environment issues, writing a few lines of code to completely automate that process felt like a superpower. I'm starting this blog to document my journey in real-time. I'm currently diving deep into: 🔹 Java 21 (the newest LTS—highly recommend checking out Virtual Threads!) 🔹 Spring Boot & enterprise backend architecture 🔹 Docker & containerization 🔹 Next up: CI/CD pipelines and Infrastructure as Code (Terraform) If you are currently stuck in IT Support or SysAdmin roles and dreaming of becoming a DevOps or Software Engineer—you aren't alone. Let's learn toge

2026-07-12 原文 →
AI 资讯

Docker Volumes vs Bind Mounts: Where Your Data Actually Lives

A container's writable layer feels like a filesystem, and that's exactly the trap. Write a database into it, remove the container, and the data is gone — no warning, no recovery. If you want anything to survive docker rm , it has to live outside the container, and Docker gives you three ways to do that: named volumes, bind mounts, and tmpfs. Knowing which one to reach for is most of the battle. Why the writable layer betrays you Every running container gets a thin read-write layer stacked on top of its image layers. It looks persistent because you can docker exec in and see your files. But that layer is bound to the container's lifecycle. docker run --name scratch alpine sh -c 'echo hello > /data.txt; cat /data.txt' # hello docker rm scratch # the layer — and /data.txt — no longer exists There's no "oops." The writable layer is discarded with the container. Persistence is not a default you get; it's a decision you make. That decision is a volume, a bind mount, or tmpfs. Named volumes: the default for state A named volume is storage that Docker creates and manages for you. You give it a name, Docker keeps the actual bytes under its own directory, and you never have to care where that is. docker volume create pgdata docker run -d --name db \ --mount type = volume,source = pgdata,target = /var/lib/postgresql/data \ postgres:16 The container writes to /var/lib/postgresql/data , but those bytes land in a Docker-managed location on the host. Remove and recreate the container against the same volume and the data is still there. docker rm -f db docker run -d --name db \ --mount type = volume,source = pgdata,target = /var/lib/postgresql/data \ postgres:16 # same data, new container Where do the bytes actually live? Under Docker's data root, typically /var/lib/docker/volumes/<name>/_data : docker volume inspect pgdata --format '{{ .Mountpoint }}' # /var/lib/docker/volumes/pgdata/_data The point is that you're not supposed to reach into that path directly — Docker owns it. You

2026-07-11 原文 →
AI 资讯

How to usar Docker networks na pratica

Quando voce cria um container e depois outro, eles podem nao se enxergar. O motivo quase sempre e a rede. Entender os tipos de rede que o Docker oferece resolve isso de uma vez. Comece listando as redes que ja existem no seu Docker. docker network ls A rede bridge e a rede host vem de fabrica. Nenhuma delas oferece resolucao de nomes entre containers. Para isso voce precisa criar a sua propria rede. docker network create minha-rede Agora os containers que entrarem nessa rede conseguem se comunicar pelo nome do container. docker run -d --name app1 --network minha-rede nginx docker run -d --name app2 --network minha-rede alpine sleep 3600 Teste a comunicacao. docker exec app2 ping app1 -c 2 O ping funciona. O DNS interno do Docker resolve app1 para o IP interno do container. Isso resolve 90% dos problemas de comunicacao. A rede bridge padrao nao tem esse recurso. Crie sua propria rede sempre que precisar que containers se enxerguem. Agora a rede host. Ela elimina o isolamento de rede. O container usa a placa do host diretamente, sem NAT e sem mapeamento de porta. docker run -d --name web-host --network host nginx O nginx fica acessivel em http://localhost:80 direto. Sem -p 80:80. Mas so um container pode usar cada porta, porque a porta e a do host de verdade. Para ambientes com mais de uma maquina, existe a rede overlay. Ela precisa do Docker Swarm ou de um cluster. docker swarm init docker network create -d overlay rede-overlay docker service create --name api --network rede-overlay --replicas 3 nginx Os containers em maquinas diferentes se enxergam pelo nome como se estivessem na mesma maquina. No dia a dia, a rede bridge personalizada resolve quase todo caso de uso. Host e para performance ou casos especificos. Overlay e para quando voce escala para mais de uma maquina. That's all for now. Thanks for reading!

2026-07-11 原文 →
AI 资讯

7 Dockerfile Mistakes That Are Quietly Costing You

Most Dockerfiles work. That's the problem — "it builds and runs" hides a lot of quiet costs in security, speed, and size that don't announce themselves until an audit, an incident, or a cloud bill does it for them. Here are seven mistakes I see constantly, and what to do instead. 1. Running as root By default, the process in your container runs as root — and if someone breaks out, they're root on a surface they shouldn't be. Add a non-root user and switch to it: RUN useradd --system --uid 10001 appuser USER appuser Cheap, and it closes off a whole category of "well, at least it wasn't root" incidents. 2. FROM some-image:latest latest is not a version — it's "whatever was newest when this happened to build." Two builds a week apart can produce different images with no diff to explain it, and a surprise base upgrade is a fun way to spend a Friday. Pin a specific tag, ideally by digest: FROM node:20.11.1-slim 3. Baking secrets into layers COPY .env . or ARG API_KEY followed by using it — and now the secret lives in an image layer forever , recoverable by anyone who pulls the image, even if a later layer deletes the file. Layers are immutable and additive; you can't delete your way out of a leak. Use build secrets ( --mount=type=secret ) or inject at runtime, never at build. 4. No .dockerignore Without one, COPY . . sweeps your .git directory, local env files, node_modules , and test data into the build context — bloating the image and, worse, potentially baking credentials and history into a layer. A five-line .dockerignore is one of the highest-leverage files in the repo. 5. Layer order that destroys your cache COPY . . RUN npm ci # ← reinstalls on EVERY code change Docker invalidates every layer after the first change. Copy the lockfile and install dependencies before copying the rest of your source, so a one-line code change doesn't trigger a full reinstall. This is a build-speed bug hiding as a style choice. 6. Leaving package manager cruft in the image RUN apt-get

2026-07-08 原文 →
AI 资讯

Part 1 — Container hoá app & chạy trong Kubernetes local

Bạn sẽ học gì Sau bài này, bạn sẽ tự tay đưa một app từ số 0 (một thư mục trống) đến chạy được bên trong một cluster Kubernetes chạy trên máy của bạn . Cụ thể: Viết một app Todo API nhỏ bằng Node.js + Express. Đóng gói (container hoá) nó thành một Docker image. Tạo một cluster Kubernetes local bằng kind . Deploy app bằng file YAML "thật" (không dùng lệnh tắt) để hiểu Kubernetes vận hành thế nào. Truy cập app đang chạy trong cluster từ máy của bạn. Đây là Part 1 trong series "DevOps 101 — Học K8s, Helm, ArgoCD từ số 0" . Cả series dùng chung một app tên todo-ops , các part sau sẽ xây tiếp lên nền này (thêm database, config, ingress, Helm, GitOps với ArgoCD). Điều kiện tiên quyết Docker (hoặc Docker Desktop / OrbStack) — đang chạy. kind — công cụ tạo cluster Kubernetes trong Docker. kubectl — CLI để nói chuyện với Kubernetes. Node.js 20+ và npm — để chạy thử app local. git — để quản lý mã nguồn. Cài đặt Chọn theo hệ điều hành của bạn. macOS (dùng Homebrew — nếu chưa có, cài trước): # Cài Homebrew (bỏ qua nếu đã có) /bin/bash -c " $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh ) " # Docker Desktop (hoặc OrbStack: brew install --cask orbstack) brew install --cask docker # Các CLI còn lại brew install kind kubectl node git Sau khi cài xong, mở Docker Desktop (hoặc OrbStack) và chờ nó báo Running trước khi chạy tiếp. Linux (Ubuntu/Debian): # Docker Engine curl -fsSL https://get.docker.com | sh sudo usermod -aG docker " $USER " # cho phép chạy docker không cần sudo (đăng xuất/đăng nhập lại để có hiệu lực) # kubectl curl -LO "https://dl.k8s.io/release/ $( curl -Ls https://dl.k8s.io/release/stable.txt ) /bin/linux/amd64/kubectl" sudo install -m 0755 kubectl /usr/local/bin/kubectl && rm kubectl # kind curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 sudo install -m 0755 kind /usr/local/bin/kind && rm kind # Node.js 20 (qua NodeSource) + git curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt-get insta

2026-07-08 原文 →
AI 资讯

Deploying SFTPGo as an Azure Storage SFTP Alternative on Linux

Azure Storage SFTP is Microsoft's managed file transfer service on top of Azure Blob Storage, convenient, but billed continuously per endpoint (roughly $0.30/hour, ~$220/month) and tied to Azure AD. SFTPGo is an open-source file transfer server offering SFTP, FTP/S, and WebDAV with pluggable storage backends (local disk, Azure Blob, S3-compatible, GCS) and no per-endpoint charge. This guide deploys SFTPGo with Docker Compose and Traefik, sets up user auth (password + SSH key + 2FA), connects S3-compatible object storage, and covers the migration path from Azure Storage SFTP. By the end, you'll have a self-hosted file transfer server with the same capabilities at zero endpoint cost. Azure Storage SFTP → SFTPGo Mapping Azure Storage SFTP SFTPGo Equivalent Notes SFTP Endpoint SFTPGo SFTP Server Configurable port, default 2022 Azure Blob Storage Azure Blob backend Native support; point at the same container, no migration needed Azure AD Authentication LDAP/OIDC plugin External identity provider via plugin Local Users Web UI / REST API user management Hierarchical Namespace Virtual directories No HNS requirement Azure Monitor Built-in logging + webhooks/syslog Prerequisite: Linux server with Docker + Compose, a DNS A record for your domain, and (if migrating) an existing Azure Storage account with SFTP enabled plus the Azure CLI installed locally. Deploy with Docker Compose 1. Create the project directories: $ mkdir -p ~/sftpgo/ { data,config } $ cd ~/sftpgo 2. Create the environment file: $ nano .env DOMAIN = sftp.example.com LETSENCRYPT_EMAIL = admin@example.com 3. Create the Compose manifest: $ nano docker-compose.yml services : traefik : image : traefik:v3.6 container_name : traefik command : - " --providers.docker=true" - " --providers.docker.exposedbydefault=false" - " --entrypoints.web.address=:80" - " --entrypoints.websecure.address=:443" - " --entrypoints.web.http.redirections.entrypoint.to=websecure" - " --certificatesresolvers.letsencrypt.acme.httpchallenge=tr

2026-07-08 原文 →
AI 资讯

Deploying ClearML as a GCP Vertex AI Alternative on Ubuntu

Google Vertex AI is Google Cloud's managed ML platform with experiment tracking, training jobs, pipelines, a model registry, and endpoints, but it locks you into GCP-specific APIs and per-use billing. ClearML is an open-source MLOps platform that covers the same ground on any Docker host or Kubernetes cluster, capturing training metrics automatically with no code changes and keeping every byte of data on infrastructure you control. This guide deploys ClearML Server with Docker Compose and Traefik, registers an agent, runs an experiment, builds a pipeline, runs a hyperparameter sweep, and deploys a Triton-served model. By the end, you'll have a self-hosted Vertex AI replacement covering the full ML lifecycle. Vertex AI → ClearML Mapping GCP Vertex AI ClearML Equivalent Purpose Vertex AI Workbench ClearML Web UI Browser-based monitoring and configuration Vertex AI Experiments ClearML Experiment Manager Automatic hyperparameter/metric/artifact tracking Vertex AI Training Job ClearML Agent + Tasks Any machine becomes a remote worker via queues Vertex AI Pipelines ClearML Pipelines Python-native DAGs, no separate compile step Vertex AI Model Registry ClearML Model Repository Versioned models with full lineage Vertex AI Endpoints ClearML Serving (Triton) Self-hosted inference with canary/A-B support Cloud Monitoring/Logging ClearML Scalars/Plots Built-in metrics and hardware dashboards Prerequisite: Ubuntu host with Docker + Compose, DNS A records for app.clearml.example.com , api.clearml.example.com , files.clearml.example.com . NVIDIA Container Toolkit if you'll run GPU agents. Deploy the ClearML Server 1. Raise Elasticsearch's virtual memory limit and restart Docker: $ echo "vm.max_map_count=524288" | sudo tee /etc/sysctl.d/99-clearml.conf $ sudo sysctl --system $ sudo systemctl restart docker 2. Create persistent data directories with the correct ownership: $ sudo mkdir -p /opt/clearml/ { data/elastic_7,data/mongo_4/db,data/mongo_4/configdb,data/redis,data/fileserver,

2026-07-08 原文 →
AI 资讯

Deploying Matomo Analytics - An Open-Source Google Analytics Alternative

Matomo is an open-source web analytics platform that keeps full ownership of visitor data on infrastructure you control, a privacy-first alternative to Google Analytics. This guide deploys Matomo using Docker Compose with a MariaDB backend, Nginx as the entry point, and Certbot issuing the TLS certificate before the stack goes live. By the end, you'll have Matomo tracking a website with a signed HTTPS certificate at your domain. Prepare Docker $ sudo usermod -aG docker $USER $ newgrp docker Set Up the Project 1. Create the project directory: $ mkdir matomo && cd matomo 2. Open the firewall: $ sudo ufw allow 80/tcp $ sudo ufw allow 443/tcp 3. Create the environment file: $ nano .env MYSQL_ROOT_PASSWORD = your_strong_mysql_root_password MYSQL_PASSWORD = your_strong_mysql_matomo_password Use passwords of at least 16 characters. 4. Create the Nginx config: $ mkdir nginx $ nano nginx/matomo.conf server { listen 80 ; server_name matomo.example.com ; location /.well-known/acme-challenge/ { root /var/www/certbot ; } location / { return 301 https:// $host$request_uri ; } } server { listen 443 ssl http2 ; server_name matomo.example.com ; ssl_certificate /etc/letsencrypt/live/matomo.example.com/fullchain.pem ; ssl_certificate_key /etc/letsencrypt/live/matomo.example.com/privkey.pem ; location / { proxy_pass http://app:80 ; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; } } Replace every matomo.example.com occurrence with your domain — it appears in both server blocks and the certificate paths. Deploy with Docker Compose $ nano docker-compose.yaml services : db : image : mariadb:11.4 command : --max-allowed-packet=64MB restart : always volumes : - matomo-db-data:/var/lib/mysql environment : - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_DATABASE=matomo - MYSQL_USER=matomo - MYSQL_PASSWORD=${MYSQL_PASSWORD} networks : - matomo-net app : image

2026-07-08 原文 →