<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/ve6kmrrs9" -->

---
title: Docker Images I'd Actually Ship: A Production Checklist
description: A production Docker checklist argues most Dockerfiles in the wild are dev setups disguised as production images, with symptoms like 1.2GB images, root...
canonical: https://daily.dev/posts/ve6kmrrs9
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Docker Images I'd Actually Ship: A Production Checklist | daily.dev
og:description: A production Docker checklist argues most Dockerfiles in the wild are dev setups disguised as production images, with symptoms like 1.2GB images, root...
og:url: https://daily.dev/posts/ve6kmrrs9
og:image: https://api.daily.dev/og/posts/VE6KmRRs9.png
og:image:alt: Post cover image
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Images I'd Actually Ship: A Production Checklist

**[PHP Dev](https://daily.dev/sources/phpdev)** · [@damienseguy](https://daily.dev/damienseguy) · 62 upvotes · 7 comments

## Summary

A production Docker checklist argues most Dockerfiles in the wild are dev setups disguised as production images, with symptoms like 1.2GB images, root processes, and baked-in secrets. The fix is multi-stage builds, separating a builder stage from a slim runtime stage, which usually cuts image size by more than half. It recommends debian-slim or distroless/static base images, ordering layers so dependencies are copied before source code, and always running as non-root. A Go binary built with distroless/static is about 15MB, compared with the 1GB PHP-FPM image the author started from. For PHP, it suggests disabling xdebug, tuning OPcache, and considering FrankenPHP to skip the FPM/nginx split.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://dev.to/parsaaftabi/docker-images-id-actually-ship-a-production-checklist-hel>

## Community discussion

Top comments from developers on daily.dev.

**@trevorsuna** · 7 upvotes

> Image size is useful, but the production checklist should optimize for repeatability and containment too. Multi-stage builds, non-root users, pinned base-image digests, an SBOM, and a minimal runtime together give better results than chasing the smallest possible image alone.

**@skepagent** · 4 upvotes

> 先拷依赖、后拷源码这一条最容易被忽略，缓存一失效就全量重建；另外 15MB 的 distroless 和 1GB 的 PHP-FPM 对比很直观，非 root 运行也该是默认项而不是可选项。

**@gaburayondev** · 3 upvotes

> Good checklist. One PHP-specific addition: pinning base images makes builds repeatable, but it also pins you to whatever vulnerabilities that image has. With the PHP2Shell runtime bugs this week, anyone with a pinned `php:8.4.26-fpm` digest is stuck on the vulnerable version until they rebuild. So pin by digest, but add a scheduled rebuild or a Renovate/Dependabot bump, and check Dockerfiles, CI and Helm charts for hardcoded PHP versions. Also, the 15MB Go vs 1GB PHP-FPM comparison isn’t quite fair. PHP can’t go distroless/static, but a slim or Alpine FPM image with only the extensions you...

**@sinarezaei** · 2 upvotes

> One thing I'd add here is how secrets are handled during the build itself, not just at runtime.
>
> I've seen this become a problem when a Docker build needs to pull private packages. A team passes an npm token or Composer credentials through `ARG`, assuming the multi-stage build keeps everything safe because the final stage doesn't copy those files.
>
> But intermediate layers and build metadata are a different story.
>
> BuildKit's `--mount=type=secret` is a much better fit for this:
>
> ```
> RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
>     npm ci --omit=dev
> ```
>
> The credentials are available...

## Similar posts on daily.dev

- [Building smaller Docker images faster](https://daily.dev/posts/building-smaller-docker-images-faster-pkye16mw7) · Lobsters · 3 upvotes · 0 comments
- [Container Security Checklist for CI/CD Pipelines: 30 Checks From Commit to Runtime](https://daily.dev/posts/container-security-checklist-for-ci-cd-pipelines-30-checks-from-commit-to-runtime-cfau8ammb) · Security Boulevard · 0 upvotes · 1 comments
- [Why To Use A Multi-Stage Dockerfile](https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt) · RUBYLAND · 0 upvotes · 0 comments

---

Tags: [#devops](https://daily.dev/tags/devops), [#golang](https://daily.dev/tags/golang), [#docker](https://daily.dev/tags/docker), [#php](https://daily.dev/tags/php), [#containers](https://daily.dev/tags/containers), [#devsecops](https://daily.dev/tags/devsecops)

[View this post on daily.dev](https://daily.dev/posts/ve6kmrrs9)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"DiscussionForumPosting","mainEntityOfPage":"https://daily.dev/posts/ve6kmrrs9","headline":"Docker Images I'd Actually Ship: A Production Checklist","text":"Shared: Docker Images I'd Actually Ship: A Production Checklist","url":"https://daily.dev/posts/ve6kmrrs9","datePublished":"2026-10-17T14:28:07.435Z","dateModified":"2026-10-17T14:28:47.268Z","author":{"@type":"Person","name":"Damien seguy","url":"https://daily.dev/damienseguy","image":"https://media.daily.dev/image/upload/s--nPbjKqol--/f_auto,q_auto/v1698422671/avatars/avatar_G85JhYcDxAg024Omc8Rlp","description":"PHP developer passionate about deep language knowledge, testing, static analysis, and sustainable it","worksFor":{"@type":"Organization","name":"Exakat","logo":"https://media.daily.dev/image/upload/s--ibtl6fze--/f_auto/v1749051132/companies/exakat"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"EndorseAction"},"userInteractionCount":41200}},"image":"https://media.daily.dev/image/upload/s--0_ODbtD2--/f_auto/v1722860399/public/Placeholder%2008","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":62},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":7}],"sharedContent":{"@type":"WebPage","url":"https://api.daily.dev/r/9fgyLZhII"},"comment":[{"@type":"Comment","text":"Image size is useful, but the production checklist should optimize for repeatability and containment too. Multi-stage builds, non-root users, pinned base-image digests, an SBOM, and a minimal runtime together give better results than chasing the smallest possible image alone.","datePublished":"2026-10-23T04:31:42.009Z","url":"https://daily.dev/posts/VE6KmRRs9#c-ZwiycO8f3","author":{"@type":"Person","name":"Trevor Suna","url":"https://daily.dev/trevorsuna","image":"https://media.daily.dev/image/upload/s--dZ7gXxpp--/f_auto/v1784081551/avatars/avatar_EMoP47rpuw8DNjhp6R1b6?_a=BAMAMicg0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":7}},{"@type":"Comment","text":"先拷依赖、后拷源码这一条最容易被忽略，缓存一失效就全量重建；另外 15MB 的 distroless 和 1GB 的 PHP-FPM 对比很直观，非 root 运行也该是默认项而不是可选项。","datePublished":"2026-10-26T02:50:27.766Z","url":"https://daily.dev/posts/VE6KmRRs9#c-xpC4Z1IY3","author":{"@type":"Person","name":"kris gu","url":"https://daily.dev/skepagent","image":"https://lh3.googleusercontent.com/a/ACg8ocJnnwFKNx7PJNhb7W6mFWr2k2SV_VHW_9ainY71DX_dv79frQ=s96-c"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":4}},{"@type":"Comment","text":"Good checklist. One PHP-specific addition: pinning base images makes builds repeatable, but it also pins you to whatever vulnerabilities that image has. With the PHP2Shell runtime bugs this week, anyone with a pinned php:8.4.26-fpm digest is stuck on the vulnerable version until they rebuild. So pin by digest, but add a scheduled rebuild or a Renovate/Dependabot bump, and check Dockerfiles, CI and Helm charts for hardcoded PHP versions. Also, the 15MB Go vs 1GB PHP-FPM comparison isn’t quite fair. PHP can’t go distroless/static, but a slim or Alpine FPM image with only the extensions you need, OPcache tuned and xdebug absent, gets you a long way.","datePublished":"2026-10-27T12:18:41.299Z","url":"https://daily.dev/posts/VE6KmRRs9#c-pTYQBwNhh","author":{"@type":"Person","name":"GabuRayonDev","url":"https://daily.dev/gaburayondev","image":"https://media.daily.dev/image/upload/s--5hPC52y_--/f_auto/v1773412842/avatars/avatar_8fkdziGASnSSBES6c4Ml9?_a=BAMAMiiu0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":3}},{"@type":"Comment","text":"One thing I’d add here is how secrets are handled during the build itself, not just at runtime.\nI’ve seen this become a problem when a Docker build needs to pull private packages. A team passes an npm token or Composer credentials through ARG, assuming the multi-stage build keeps everything safe because the final stage doesn’t copy those files.\nBut intermediate layers and build metadata are a different story.\nBuildKit’s --mount=type=secret is a much better fit for this:\nRUN --mount=type=secret,id=npmrc,target=/root/.npmrc \\\n    npm ci --omit=dev\n\nThe credentials are available only during that build instruction instead of being baked into the resulting layer.\nI’d also make sure CI doesn’t accidentally print the secret or write it into a generated config file. Keeping credentials out of the final image is only half the job. Keeping them out of the entire build process’s artifacts and logs matters just as much.","datePublished":"2026-10-31T12:01:28.852Z","url":"https://daily.dev/posts/VE6KmRRs9#c-1dUNerJbf","author":{"@type":"Person","name":"Sina Rezaei","url":"https://daily.dev/sinarezaei","image":"https://lh3.googleusercontent.com/a/ACg8ocLXjJ5mCeyMCQK6CSjPfPxZisLuVwj3KOgnAtXoJoPAAsuvSrxh=s96-c"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2}}],"isPartOf":{"@type":"WebPage","url":"https://daily.dev/squads/phpdev","name":"PHP Dev"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"PHP Dev","item":"https://daily.dev/squads/phpdev"},{"@type":"ListItem","position":3,"name":"Docker Images I'd Actually Ship: A Production Checklist"}]}
```

