<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Docker &#8211; LinuxTips</title>
	<atom:link href="https://linuxtips.ca/category/docker/feed/" rel="self" type="application/rss+xml" />
	<link>https://linuxtips.ca</link>
	<description>All things Linux and C</description>
	<lastBuildDate>Mon, 17 Aug 2026 21:42:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>

<image>
	<url>https://linuxtips.ca/wp-content/uploads/2026/07/cropped-linux-tux-logo-png_seeklogo-492036-32x32.png</url>
	<title>Docker &#8211; LinuxTips</title>
	<link>https://linuxtips.ca</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>syntax=docker/dockerfile:1.4</title>
		<link>https://linuxtips.ca/2026/08/17/syntaxdocker-dockerfile1-4/</link>
					<comments>https://linuxtips.ca/2026/08/17/syntaxdocker-dockerfile1-4/#respond</comments>
		
		<dc:creator><![CDATA[schweige]]></dc:creator>
		<pubDate>Mon, 17 Aug 2026 21:42:21 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<guid isPermaLink="false">https://linuxtips.ca/2026/08/17/syntaxdocker-dockerfile1-4/</guid>

					<description><![CDATA[Title: Docker Images Demystified – A Complete Guide to Building, Optimizing, and Deploying Lightweight Containers &#8212; Introduction – Why Docker Images Are the Real Superheroes of Modern DevOps If you’ve ever tried to explain Docker to a non‑technical friend, you might have said something like, “It’s a way to package an app so it runs ... <a title="syntax=docker/dockerfile:1.4" class="read-more" href="https://linuxtips.ca/2026/08/17/syntaxdocker-dockerfile1-4/" aria-label="Read more about syntax=docker/dockerfile:1.4">Read more</a>]]></description>
										<content:encoded><![CDATA[<p><strong>Title: Docker Images Demystified – A Complete Guide to Building, Optimizing, and Deploying Lightweight Containers</strong></p>
<p>&#8212;</p>
<h2>Introduction – Why Docker Images Are the Real Superheroes of Modern DevOps  </h2>
<p>If you’ve ever tried to explain Docker to a non‑technical friend, you might have said something like, “It’s a way to package an app so it runs the same everywhere.” While that’s true, the <em>real</em> magic lives in the <strong>Docker image</strong> – the immutable blueprint that makes containers so reliable, portable, and fast.</p>
<p>Think of a Docker image as a layered, version‑controlled snapshot of everything your application needs: the operating system libraries, runtime, code, configuration files, and even security patches. When you spin up a container from that image, you get an isolated, reproducible environment that behaves exactly the same on a developer’s laptop, a staging server, or a production Kubernetes cluster.</p>
<p>In today’s hyper‑competitive software landscape, mastering Docker images isn’t just a nice‑to‑have skill; it’s a competitive advantage. Optimized images shave seconds off startup time, cut cloud costs, improve security posture, and streamline CI/CD pipelines. In this 2,000‑word deep dive, we’ll walk through everything you need to know to <strong>build, optimize, secure, and deploy Docker images</strong> like a pro.</p>
<p>Grab a coffee, fire up your favorite code editor, and let’s unlock the full potential of Docker images together.</p>
<p>&#8212;</p>
<h2>1. Understanding the Anatomy of a Docker Image  </h2>
<h3>1.1 What Exactly Is a Docker Image?  </h3>
<p>A Docker image is a <strong>read‑only template</strong> that contains a series of <strong>layers</strong> stacked on top of each other. Each layer represents a set of filesystem changes (files added, modified, or deleted) and is immutable once created. When you run `docker run`, Docker assembles those layers into a <strong>union filesystem</strong>, creating a writable container on top of the immutable image.</p>
<p><strong>Key concepts</strong></p>
<p>| Term | Meaning |<br />
|&#8212;&#8212;|&#8212;&#8212;&#8212;-|<br />
| <strong>Base Image</strong> | The foundational layer, often an official OS (e.g., `ubuntu:22.04`, `alpine:3.18`) or language runtime (`node:20-alpine`). |<br />
| <strong>Layer</strong> | A diff of filesystem changes; each `RUN`, `COPY`, or `ADD` command in a Dockerfile creates a new layer. |<br />
| <strong>Image ID</strong> | A SHA256 hash uniquely identifying the image content. |<br />
| <strong>Tag</strong> | Human‑readable alias (e.g., `myapp:1.2.0`); multiple tags can point to the same image ID. |<br />
| <strong>Manifest</strong> | JSON document describing the image’s layers, architecture, and config. |</p>
<p>Because layers are <strong>content‑addressable</strong>, Docker can reuse them across multiple images. If two images share the same base layer, Docker only stores that layer once on the host, saving disk space and speeding up pulls.</p>
<h3>1.2 The Dockerfile – Blueprint for Your Image  </h3>
<p>A <strong>Dockerfile</strong> is a plain‑text script that tells Docker how to build an image. Each instruction translates into a layer (except `ARG` and `FROM` under certain conditions). Here’s a minimal example:</p>
<p>&#8220;`Dockerfile</p>
<p>FROM node:20-alpine AS builder<br />
WORKDIR /app<br />
COPY package*.json ./<br />
RUN npm ci &#8211;only=production<br />
COPY . .<br />
RUN npm run build</p>
<p>FROM nginx:alpine<br />
COPY &#8211;from=builder /app/dist /usr/share/nginx/html<br />
EXPOSE 80<br />
CMD [&#8220;nginx&#8221;, &#8220;-g&#8221;, &#8220;daemon off;&#8221;]<br />
&#8220;`</p>
<p>Notice the <strong>multi‑stage build</strong>: the first stage compiles the app, the second stage copies only the built artifacts into a lightweight Nginx image. This technique dramatically reduces final image size—a best practice we’ll explore later.</p>
<h3>1.3 Image Registries – Where Images Live  </h3>
<p>Once built, images are pushed to a <strong>Docker registry</strong> so other machines can pull them. Popular options include:</p>
<ul>
<li><strong>Docker Hub</strong> – The default public registry; great for open‑source projects.</li>
<li><strong>GitHub Container Registry (GHCR)</strong> – Integrated with GitHub Actions, supports fine‑grained permissions.</li>
<li><strong>Amazon Elastic Container Registry (ECR)</strong>, <strong>Google Artifact Registry</strong>, <strong>Azure Container Registry</strong> – Cloud‑native options with IAM integration.</li>
<li><strong>Harbor</strong> – Self‑hosted, enterprise‑grade registry with vulnerability scanning.</li>
<p>Choosing the right registry depends on your security requirements, geographic latency, and cost model.</p>
<p>&#8212;</p>
<h2>2. Building Efficient Docker Images – Best Practices &amp; Tips  </h2>
<h3>2.1 Keep Images Small – Why Size Matters  </h3>
<li><strong>Faster Pulls:</strong> Smaller images reduce network latency, especially in edge locations or CI runners.</li>
<li><strong>Lower Attack Surface:</strong> Fewer packages mean fewer vulnerabilities to patch.</li>
<li><strong>Cost Savings:</strong> Cloud providers often charge per GB transferred and stored; slimmer images translate directly into lower bills.</li>
<p>#### 2.1.1 Choose the Right Base Image</p>
<p>| Base Image | Typical Size | Use Cases |<br />
|&#8212;&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;&#8211;|<br />
| `alpine` | ~5 MB | Simple Go, Node, Python apps where you can compile statically or rely on musl. |<br />
| `debian:slim` | ~22 MB | When you need glibc compatibility but still want a lean footprint. |<br />
| `ubuntu` | ~70 MB | Full‑featured environments, legacy binaries requiring specific libraries. |<br />
| Language‑specific images (e.g., `node:20-alpine`) | Varies | Provides runtime + common tooling out‑of‑the‑box. |</p>
<p><strong>Tip:</strong> Start with `*-slim` or `alpine` and only add what you truly need. If a library refuses to compile on Alpine due to musl/glibc incompatibility, consider `debian:slim` instead of the full Ubuntu.</p>
<h3>2.2 Leverage Multi‑Stage Builds  </h3>
<p>Multi‑stage builds let you separate <strong>build</strong> and <strong>runtime</strong> environments. The build stage can contain heavy compilers, package managers, and intermediate artifacts, while the final stage contains only the runtime dependencies.</p>
<p><strong>Example: Go Application</strong></p>
<p>&#8220;`Dockerfile</p>
<h1>Stage 1 – Build</h1>
<p>
FROM golang:1.22-alpine AS builder<br />
WORKDIR /src<br />
COPY go.mod go.sum ./<br />
RUN go mod download<br />
COPY . .<br />
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /app/main .</p>
<h1>Stage 2 – Runtime</h1>
<p>FROM alpine:3.18<br />
RUN adduser -D -g &#8221; appuser<br />
USER appuser<br />
COPY &#8211;from=builder /app/main /usr/local/bin/app<br />
ENTRYPOINT [&#8220;app&#8221;]<br />
&#8220;`</p>
<p>Result: A final image of ~8 MB, compared to &gt;100 MB if you shipped the entire Go toolchain.</p>
<h3>2.3 Order Dockerfile Instructions for Layer Caching  </h3>
<p>Docker caches each layer after it’s built. If a layer’s content hasn’t changed, Docker reuses the cached version on subsequent builds, dramatically speeding up CI pipelines.</p>
<p><strong>Best ordering pattern:</strong></p>
<p>1. <strong>Set the base image</strong> (`FROM`).<br />
2. <strong>Install OS packages</strong> (`RUN apt-get update &amp;&amp; apt-get install -y …`).  <br />
   <em>These rarely change, so they stay cached longest.</em><br />
3. <strong>Add language‑specific dependencies</strong> (`COPY package*.json .` + `RUN npm ci`).  <br />
   <em>Only invalidated when dependency files change.</em><br />
4. <strong>Copy source code</strong> (`COPY . .`).  <br />
   <em>Invalidated on any code change, but the heavy layers above stay cached.</em><br />
5. <strong>Run build steps</strong> (`RUN npm run build`).  <br />
   <em>Only runs when source changes.</em></p>
<p>By grouping immutable steps early, you avoid rebuilding the entire stack on each commit.</p>
<h3>2.4 Minimize the Number of Layers  </h3>
<p>While Docker automatically creates a layer per instruction, you can combine commands using `&amp;&amp;` or &#8220; to reduce the total layer count. Fewer layers mean a smaller manifest and slightly faster extraction.</p>
<p>&#8220;`Dockerfile<br />
RUN apt-get update &amp;&amp; apt-get install -y <br />
    curl <br />
    git <br />
    &amp;&amp; rm -rf /var/lib/apt/lists/*<br />
&#8220;`</p>
<p><strong>Caution:</strong> Over‑combining can make Dockerfiles harder to read and debug. Strike a balance between readability and layer optimization.</p>
<h3>2.5 Clean Up After Installations  </h3>
<p>Package managers often leave caches (e.g., `apt` lists, `npm` cache) that bloat the image. Always purge them in the same `RUN` statement that installs the packages.</p>
<p>&#8220;`Dockerfile<br />
RUN apk add &#8211;no-cache git &amp;&amp; <br />
    npm ci &#8211;only=production &amp;&amp; <br />
    npm cache clean &#8211;force<br />
&#8220;`</p>
<p>For `apt`‑based images, use `&#8211;no-install-recommends` and clean `/var/lib/apt/lists/*`.</p>
<h3>2.6 Use `.dockerignore` Effectively  </h3>
<p>A `.dockerignore` file works like `.gitignore`—it tells Docker which files <strong>not</strong> to send to the daemon during the build context upload. Excluding large directories (e.g., `node_modules`, `target`, `.git`) reduces build time and prevents accidental inclusion of secrets.</p>
<p>&#8220;`text</p>
<h1>.dockerignore</h1>
<p>
.git<br />
node_modules<br />
*.log<br />
Dockerfile<br />
.dockerignore<br />
&#8220;`</p>
<h3>2.7 Tag Images Properly – Semantic Versioning &amp; Immutable Tags  </h3>
<p>Tagging helps teams locate the right image quickly. Adopt a convention such as:</p>
<li>`myapp:1.2.3` – Full semantic version for releases.</li>
<li>`myapp:1.2` – Minor‑level tag pointing to the latest patch.</li>
<li>`myapp:latest` – Points to the most recent stable build (use with caution in production).</li>
<p>Avoid mutable tags like `dev` that change unpredictably; they make rollbacks harder.</p>
<p>&#8212;</p>
<h2>3. Securing Docker Images – From Build to Runtime  </h2>
<h3>3.1 Scan for Vulnerabilities  </h3>
<p>Every layer can contain known CVEs. Integrate automated scanning into your CI pipeline:</p>
<p>| Tool | Integration | Highlights |<br />
|&#8212;&#8212;|&#8212;&#8212;&#8212;&#8212;-|&#8212;&#8212;&#8212;&#8212;|<br />
| <strong>Trivy</strong> | GitHub Actions, GitLab CI, Jenkins | Fast, supports SBOM, CVE database updates daily. |<br />
| <strong>Clair</strong> | Kubernetes, Harbor | Open‑source, REST API, works with registries. |<br />
| <strong>Snyk</strong> | Cloud‑native, CI plugins | Commercial support, detailed remediation advice. |<br />
| <strong>Docker Scout</strong> (formerly Docker Security Scanning) | Docker Hub, Docker Desktop | Native Docker experience, integrates with Docker BuildKit. |</p>
<p><strong>Sample GitHub Action using Trivy:</strong></p>
<p>&#8220;`yaml<br />
name: Scan Docker Image<br />
on:<br />
  push:<br />
    branches: [ main ]<br />
jobs:<br />
  trivy-scan:<br />
    runs-on: ubuntu-latest<br />
    steps:<br />
      &#8211; uses: actions/checkout@v4<br />
      &#8211; name: Build image<br />
        run: docker build -t myorg/app:${{ github.sha }} .<br />
      &#8211; name: Scan image<br />
        uses: aquasecurity/trivy-action@master<br />
        with:<br />
          image-ref: myorg/app:${{ github.sha }}<br />
          format: table<br />
          exit-code: &#8216;1&#8217;   # Fail the job on any vulnerability<br />
&#8220;`</p>
<h3>3.2 Adopt the Principle of Least Privilege  </h3>
<li><strong>Run as non‑root</strong> – Add a dedicated user in the Dockerfile and switch to it with `USER`.  </li>
<li><strong>Drop capabilities</strong> – Use `&#8211;cap-drop ALL` when running containers, then add only what you need (`&#8211;cap-add NET<em>BIND</em>SERVICE` for binding to port 80).  </li>
<li><strong>Read‑only filesystem</strong> – Set `&#8211;read-only` on containers that don’t need to write; mount a writable volume only for necessary paths.</li>
<p><strong>Dockerfile snippet:</strong></p>
<p>&#8220;`Dockerfile<br />
RUN addgroup -S appgroup &amp;&amp; adduser -S appuser -G appgroup<br />
USER appuser:appgroup<br />
&#8220;`</p>
<h3>3.3 Sign and Verify Images  </h3>
<p>Docker Content Trust (DCT) uses Notary v2 to cryptographically sign images. Enabling `DOCKER<em>CONTENT</em>TRUST=1` forces `docker push` and `docker pull` to verify signatures, protecting against supply‑chain attacks.</p>
<p>&#8220;`bash<br />
export DOCKER<em>CONTENT</em>TRUST=1<br />
docker push myregistry.com/myapp:1.2.3   # Signs the image<br />
docker pull myregistry.com/myapp:1.2.3   # Verifies signature<br />
&#8220;`</p>
<p>For enterprises, consider <strong>Cosign</strong> (part of the sigstore project) for keyless signing integrated with CI pipelines.</p>
<h3>3.4 Keep Base Images Updated  </h3>
<p>Even if you lock a tag like `node:20-alpine`, security patches are back‑ported. Regularly rebuild your images (e.g., nightly) to pull the latest base layers. Use a CI job that rebuilds and pushes a `-latest` tag, then triggers a rolling update in your orchestrator.</p>
<h3>3.5 Avoid Secrets in Images  </h3>
<p>Never bake API keys, passwords, or certificates into the image layers. Instead:</p>
<li>Use <strong>Docker secrets</strong> (Swarm) or <strong>Kubernetes Secrets</strong> mounted as files or env vars at runtime.  </li>
<li>Leverage <strong>environment variable injection</strong> from CI/CD tools (e.g., GitHub Actions secrets).  </li>
<li>If you must use a secret during build (e.g., private npm registry token), use BuildKit’s `&#8211;secret` flag so the secret never appears in a layer.</li>
</ul>
<p>&#8220;`Dockerfile</p>
<h1>Dockerfile</h1>
<p></p>
<h1>syntax=docker/dockerfile:1.4</h1>
<p>
FROM node:20</p>
]]></content:encoded>
					
					<wfw:commentRss>https://linuxtips.ca/2026/08/17/syntaxdocker-dockerfile1-4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
