# Docker Operations Build Docker container images using buildx. ## Operations ### Docker.Install Installs the Docker CLI in the container. Required before using Docker.Build when running with --dind. Skips if already installed. ```csharp Docker.Install(); Docker.Build("Dockerfile", o => o.WithTag("myapp:latest")); ``` ### Docker.IsAvailable Check if Docker CLI and daemon are accessible. Executes immediately (not registered as a step) and returns a boolean. Useful for conditional logic in build scripts. ```csharp if (Docker.IsAvailable()) { Docker.Build("Dockerfile", o => o.WithTag("myapp:latest")); } else { Log.Warning("Docker not available, skipping container build"); } ``` ### Docker.Build Builds a Docker image using buildx. Supports single or multi-platform builds with optional push to registry. Requires --dind CLI flag. Call Docker.Install() first to install the Docker CLI. Automatically creates a buildx builder for multi-platform builds and handles ghcr.io authentication when pushing. Recommended: Use WithPush() for atomic build+push to ensure both version and latest tags point to the same manifest. ```csharp // Recommended: Atomic multi-arch build+push to ghcr.io // Ensures all tags point to the same manifest Docker.Install(); Docker.Build("./Dockerfile", o => o .WithPlatforms("linux/amd64", "linux/arm64") .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithTag("ghcr.io/myorg/myapp:latest") .WithPush()); // Single platform build with push Docker.Build("./src/MyApp/Dockerfile", o => o .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithBuildArg("VERSION", "1.0.0") .WithPush()); // Local build only (no push, loads into local docker) Docker.Build("Dockerfile", o => o.WithTag("myapp:dev")); ``` ## Recommended: Atomic Build and Push **Best practice**: Use `Docker.Build` with `WithPush()` to build and push in a single atomic operation. This ensures: - Both version and latest tags point to the same manifest - No cache staleness issues between build and push - Multi-platform support works correctly ```csharp // Build multi-arch image and push atomically Docker.Install(); Docker.Build("./Dockerfile", o => o .WithPlatforms("linux/amd64", "linux/arm64") .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithTag("ghcr.io/myorg/myapp:latest") .WithPush()); ``` ## Basic Usage Build Docker images with static or dynamic tags. All builds use `docker buildx build` for future-proof compatibility. ```csharp // Build a Docker image (loads into local docker for testing) Docker.Build("Dockerfile", o => o.WithTag("myapp:dev")); // Build with explicit tag and push to registry Docker.Build("./src/MyApp/Dockerfile", o => o .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithPush()); ``` ## Advanced Options Configure build arguments, platform, caching, and context directory. ```csharp // Build with build arguments Docker.Build("Dockerfile", o => o .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithBuildArg("VERSION", "1.0.0") .WithBuildArg("BUILD_NUMBER", "123") .WithPush()); // Specify platform (for cross-compilation) Docker.Build("Dockerfile", o => o .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithPlatform("linux/amd64") .WithPush()); // Build without cache Docker.Build("Dockerfile", o => o .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithNoCache() .WithPush()); // Specify context directory Docker.Build("./docker/Dockerfile", o => o .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithContext("./src") .WithPush()); ``` ## Multi-Architecture Builds Build images for multiple platforms in a single command. This is useful for ARM64 support (Apple Silicon, AWS Graviton) alongside AMD64. ```csharp // Build for multiple platforms and push to registry Docker.Install(); Docker.Build("./Dockerfile", o => o .WithPlatforms("linux/amd64", "linux/arm64") .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithTag("ghcr.io/myorg/myapp:latest") .WithPush()); ``` **Note:** Multi-architecture builds with `WithPush()` require images to be pushed directly to a registry (they cannot be loaded into the local Docker daemon when building for multiple platforms). ### Multi-Platform with Build Arguments ```csharp Docker.Build("./src/MyApp/Dockerfile", o => o .WithPlatforms("linux/amd64", "linux/arm64") .WithTag("ghcr.io/myorg/myapp:v1.0.0") .WithBuildArg("VERSION", "1.0.0") .WithContext("./src") .WithPush()); ``` ## Full Workflow Example Build, push, and release a containerized application. ```csharp var version = "1.0.0"; // Build the .NET application Dotnet.Publish(app, o => o .Output(Root / "publish") .WithConfiguration(Configuration.Release)); // Build multi-arch image and push atomically Docker.Install(); Docker.Build("Dockerfile", o => o .WithPlatforms("linux/amd64", "linux/arm64") .WithTag($"ghcr.io/myorg/myapp:{version}") .WithTag("ghcr.io/myorg/myapp:latest") .WithPush()); // Create GitHub release Git.Tag($"v{version}"); Git.Push(); Git.PushTags(); GitHub.CreateRelease(o => o.WithTag($"v{version}").WithGeneratedNotes()); ``` ## Local Development For local testing without pushing to a registry: ```csharp // Build and load into local docker (no push) Docker.Build("Dockerfile", o => o.WithTag("myapp:dev")); ``` ## Options Reference ### Docker.Build Options | Option | Description | |--------|-------------| | `WithTag(string)` | Add an image tag. Can be called multiple times for multiple tags. Use full registry path for push (e.g., "ghcr.io/org/app:v1"). | | `WithPlatform(string)` | Single target platform (e.g., "linux/amd64"). Clears any existing platforms. | | `WithPlatforms(params string[])` | Multiple target platforms for multi-arch builds (e.g., "linux/amd64", "linux/arm64"). | | `WithContext(string)` | Build context directory. This is the root directory for COPY instructions in the Dockerfile. Defaults to the Dockerfile's parent directory. | | `WithBuildArg(key, value)` | Pass a build-time variable to the Dockerfile. Access in Dockerfile with `ARG key` and `${key}`. Common uses: version numbers, build timestamps, feature flags. | | `WithPush()` | **Recommended**: Push images to registry atomically during build. Ensures all tags point to the same manifest. Required for multi-platform builds. | | `WithNoCache()` | Disable build cache entirely. Forces all layers to rebuild. Use when debugging caching issues or ensuring a clean build. | | `WithoutLoad()` | Disable loading image into local docker. Useful when only pushing to a registry. | ## Notes - Docker operations require Docker to be installed on the host machine. - `Docker.Build` requires the `--dind` flag (Docker-in-Docker mode). - **CI Server**: When running on the ANDO CI Server, the Docker CLI is automatically installed in DIND build containers. `Docker.Install()` is still recommended in build scripts for portability (it is a no-op if Docker is already present). - Use `WithPush()` for atomic build+push to ensure all tags point to the same manifest. - If the dockerfile parameter is a directory, ANDO assumes the Dockerfile is inside that directory. - For multi-platform builds, ANDO automatically creates a buildx builder named `ando-builder` if one doesn't exist. - `WithPush()` automatically handles ghcr.io authentication when pushing to GitHub Container Registry (uses `GITHUB_TOKEN` or gh CLI credentials). The owner is extracted from the ghcr.io tag (e.g., `ghcr.io/myorg/myapp` → owner is `myorg`).