Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
YAML 2: Multiline Strings, Anchors/Aliases, Merge Keys, Multiple Documents and KYAML
Write scripts with |, long prose with >, and use |- for single-line values such as secrets, otherwise a \n is appended. The merge key (<<) is not in YAML 1.2: Compose, kubectl and kubeconform support it, GitHub Actions does not, and js-yaml 5 needs an option. We show multiple documents, the document boundary of anchors, unsafe tags, KYAML and a yamllint rule set for Bookstore with real output.
YAML 1: Syntax, Types and the "Norway Problem": Reading a YAML File Correctly
The type of an unquoted YAML value depends on the rule set the parser applies: in YAML 1.1 NO is false, 12:30 a number and 0755 octal; in YAML 1.2 all three differ. We run PyYAML, ruamel.yaml, js-yaml, YamlDotNet, yq, Docker Compose and kubectl on the same file and show three real type errors in Bookstore's compose.yaml and Kubernetes manifest.
Deploying with Aspire: publish, deploy and do; Docker Compose, Kubernetes and Azure Targets
aspire publish turns the AppHost into artifacts with placeholders (a Compose file, a Helm chart), aspire deploy resolves values, builds images and applies them, and aspire do runs a single pipeline step. Deploying Bookstore to Docker Compose, the post fixes a gateway that wasn't exposed, seed data leaking into production, a non-https Keycloak Authority and Angular's output folder, and covers the Helm chart, the registry requirement and Azure targets.
What Is Aspire and What Isn't It? AppHost, the App Model and How It Differs from Docker Compose and Kubernetes
Aspire is a local orchestration and observability layer that describes the parts of a multi-service app and their connections in code in an AppHost, runs them with one command and collects their telemetry in a dashboard; it isn't a production orchestrator or a service mesh. The post adds an AppHost to Bookstore with aspire init and shows the DCP proxy, the environment variables Aspire provides and why there are no traces without ServiceDefaults, with real output.
The Evolution of Compose: From docker-compose v1 to Compose v2 and v5, the Compose Specification and 2024–2026 Features
Today's Compose implements a single schema, the Compose Specification: the version field in old files is ignored, fields from the 2.x and 3.x formats are valid together, and v5 continues v2 with a Go SDK and builds handed to Bake. We run Bookstore's 2019 docker-compose.yml with docker-compose 1.25.5, 1.29.2 and Compose 5.7.1, look at the differences with real output, and map the 2024–2026 features and a migration checklist.
Compose in Production on a Single Server: Image Tags, Restart, Log Rotation, Resource Limits and the Limits of Compose
The rule for Compose in production on a single server is that the server never builds: the image is built on CI and pushed to a registry with an immutable tag, and the server pulls it with pull and up -d --wait. With real output we look at deploy and rollback for Bookstore, the 11.5-second outage up -d causes through the dependency chain, log rotation, resource limits, an entrypoint that never passes SIGTERM to sqlservr and BACKUP DATABASE as a Compose 5.6 job.
Multiple Environments: Override Files, include, extends and Merge Rules
In Compose the shared definition lives in compose.yaml and each environment writes only its difference: compose.override.yaml loads automatically when no -f is given, other files are layered with -f; maps merge, while port lists append in unexpected ways. With real output we split Bookstore into a database file with include and a shared sqlcmd definition with extends, and look at !override, !reset and a CI step with a clean tmpfs database, --wait and an exit code.
A Development Environment: Compose Watch, Hot Reload and Deciding What Runs in a Container
Compose Watch carries host changes into the running container through develop.watch rules: sync copies files and is enough for tools with hot reload, rebuild builds the image again and recreates the container. We compare dependencies-in-Compose/app-in-the-IDE, everything-in-containers and Dev Containers, and look at a 5-second rebuild for Bookstore.Api, sync for the Angular dev server and the delete-permission trap with a non-root user, all with real output.
Configuration and Secrets in Compose: environment, env_file, .env Interpolation, secrets and Profiles
.env is the file Compose reads to fill ${VAR} expressions in compose.yaml and it gives nothing to containers; passing environment variables to a container is the job of environment and env_file, passing a password as a file is the job of secrets:. With real output we look at precedence, required variables with ${VAR:?}, moving Bookstore's passwords to /run/secrets, appsettings through configs and optional services with profiles.
Service Dependencies: depends_on, Healthcheck Conditions, a Migration Service and Restart
Short depends_on only sets the start order; waiting for a service to be ready needs a health check and condition: service_healthy, and waiting for a one-off job needs service_completed_successfully. We write a health check for SQL Server, move the schema scripts into a migrate service and into Compose 5.3's pre_start init container, and test restart policies and SqlClient retry logic with real outage measurements.
Getting Started with Docker Compose: Bringing Up Bookstore with a Single compose.yaml
Docker Compose defines Bookstore's API, web and SQL Server containers, their network and volume in one compose.yaml and brings them all up together with docker compose up -d. With real output we look at the file's anatomy, build versus image, the project name, DNS by service name, the logs/exec/config commands, what down and down -v do to your data and why the version field is now obsolete.