惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
S
Security @ Cisco Blogs
V
Visual Studio Blog
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
The Cloudflare Blog
云风的 BLOG
云风的 BLOG
小众软件
小众软件
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
爱范儿
爱范儿
B
Blog RSS Feed
Recorded Future
Recorded Future
The GitHub Blog
The GitHub Blog
宝玉的分享
宝玉的分享
博客园 - 司徒正美
U
Unit 42
G
Google Developers Blog
博客园 - Franky
阮一峰的网络日志
阮一峰的网络日志
H
Hackread – Cybersecurity News, Data Breaches, AI and More
I
InfoQ
T
The Blog of Author Tim Ferriss
F
Fortinet All Blogs
博客园 - 【当耐特】
腾讯CDC
博客园 - 聂微东
IT之家
IT之家
Martin Fowler
Martin Fowler
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Recent Announcements
Recent Announcements
The Register - Security
The Register - Security
PCI Perspectives
PCI Perspectives
C
Check Point Blog
AI
AI
Webroot Blog
Webroot Blog
I
Intezer
博客园 - 三生石上(FineUI控件)
Google DeepMind News
Google DeepMind News
L
LangChain Blog
C
Cybersecurity and Infrastructure Security Agency CISA
S
Schneier on Security
C
CERT Recently Published Vulnerability Notes
Forbes - Security
Forbes - Security
S
Secure Thoughts
Y
Y Combinator Blog
Google Online Security Blog
Google Online Security Blog
H
Heimdal Security Blog
有赞技术团队
有赞技术团队
L
Lohrmann on Cybersecurity

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Docker Pitfalls I Hit (And How to Avoid Them)
Martin Oehle · 2026-04-24 · via DEV Community

Your Dockerfile builds, your container starts, and your triggers never fire. The Functions host logs "no functions found" or the container sits idle, processing nothing. The gap between a working image and a working function app is entirely configuration. The runtime needs specific environment variables, the build must publish to the exact path the host expects, and Azurite connections behave differently inside a container network than on localhost. Four walls, four fixes. All code samples are in the companion repo.

Pitfall 1: Environment Variables That Vanish

Your container starts, the Functions host initializes, and the logs show this:

[2026-04-20T08:12:03Z] No job functions found. Try making your job classes and methods public.
[2026-04-20T08:12:03Z] If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.)
[2026-04-20T08:12:03Z] make sure you've called the registration method for the extension(s)
[2026-04-20T08:12:03Z] in your startup code
[2026-04-20T08:12:03Z] 0 functions loaded

Enter fullscreen mode Exit fullscreen mode

You check your code. The classes are public. The methods are public. The bindings are registered. Everything runs fine with func start on your machine.

The error is misleading. The real cause: FUNCTIONS_WORKER_RUNTIME is not set.

Why the file you trusted does not exist here

local.settings.json is a dev-time convenience. The Azure Functions Core Tools reads it when you run func start locally. Inside a container, that file is never loaded. The container runtime reads OS environment variables only, and if FUNCTIONS_WORKER_RUNTIME is missing, the host cannot determine which language worker to start. It discovers zero functions and prints an error that sends you looking at your code instead of your configuration.

AzureWebJobsStorage is the second variable that catches people. Without it, you get a different failure:

Value cannot be null. (Parameter 'connectionString')

Enter fullscreen mode Exit fullscreen mode

Or worse, no error at all. HTTP triggers still work because they do not require storage. You test with an HTTP endpoint, everything responds, you deploy, and your queue triggers silently never fire. The host needs a storage connection to manage leases, checkpoints, and timer schedules for every non-HTTP trigger type.

If you set FUNCTIONS_WORKER_RUNTIME to dotnet instead of dotnet-isolated, the host raises AZFD0013: the configured runtime does not match the worker runtime metadata in your published artifacts. Another error that points away from the actual one-word fix.

The second trap: .env files that silently mangle values

Azure Storage connection strings are long. If your .env file wraps them across lines, Docker Compose silently truncates or corrupts the value:

# Broken: line-wrapped connection string
AzureWebJobsStorage=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;
  AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;
  BlobEndpoint=http://azurite:10000/devstoreaccount1;
  QueueEndpoint=http://azurite:10001/devstoreaccount1;

# Working: entire value on one line
AzureWebJobsStorage=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1;

Enter fullscreen mode Exit fullscreen mode

No warning, no parse error. The value just stops at the first newline.

The fix: separate constants from secrets

Bake values that never change per environment into your Dockerfile:

ENV AzureWebJobsScriptRoot=/home/site/wwwroot
ENV FUNCTIONS_WORKER_RUNTIME=dotnet-isolated

Enter fullscreen mode Exit fullscreen mode

Pass everything else through your Compose file or deployment config:

services:
  functions:
    build: .
    environment:
      - AzureWebJobsStorage=${AzureWebJobsStorage}
      - APPLICATIONINSIGHTS_CONNECTION_STRING=${APPLICATIONINSIGHTS_CONNECTION_STRING}
    env_file:
      - .env

Enter fullscreen mode Exit fullscreen mode

Connection strings and instrumentation keys stay out of the image. They come from .env locally and from app settings or Key Vault references in production.

One more if you are deploying custom containers to App Service specifically: set WEBSITES_ENABLE_APP_SERVICE_STORAGE=false. The default (true) mounts persistent storage over /home, which overwrites your published function code at startup. This does not apply to Container Apps, only App Service (GitHub issue #642).

Pitfall 2: Azurite and Docker Networking

Most tutorials tell you to set AzureWebJobsStorage to UseDevelopmentStorage=true and move on. That shorthand expands to a full connection string pointing at localhost:

DefaultEndpointsProtocol=http;
AccountName=devstoreaccount1;
AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;
BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;
QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;
TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;

Enter fullscreen mode Exit fullscreen mode

See those 127.0.0.1 addresses? When Azurite runs on your machine, that works fine. Inside Docker, it breaks.

Each container runs in its own network namespace. 127.0.0.1 inside the functions container refers to the functions container itself, not Azurite. Your function tries to reach storage on its own loopback interface, finds nothing listening, and fails silently or throws a connection error depending on the trigger type.

Docker networking: broken UseDevelopmentStorage=true vs working explicit service name

Docker Compose creates a shared bridge network where each service name resolves to the corresponding container's IP. So the fix is to spell out the full connection string with the Compose service name replacing 127.0.0.1:

DefaultEndpointsProtocol=http;
AccountName=devstoreaccount1;
AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;
BlobEndpoint=http://azurite:10000/devstoreaccount1;
QueueEndpoint=http://azurite:10001/devstoreaccount1;
TableEndpoint=http://azurite:10002/devstoreaccount1;

Enter fullscreen mode Exit fullscreen mode

azurite here is whatever you named the service in your docker-compose.yml. DNS resolution happens automatically on the Compose network.

But DNS resolving correctly is not enough. By default, Azurite binds to 127.0.0.1 inside its own container, which means it only accepts connections from itself. You need to pass --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 so Azurite listens on all interfaces. Without this, the functions container resolves azurite to the right IP, opens a TCP connection, and gets "Connection refused."

This pitfall hides well because HTTP triggers don't need storage. You build a function app, add an HTTP trigger, test it in Docker, everything works. Then you add a queue trigger and it silently does nothing: no errors in the console, no messages processed, no indication that storage is unreachable. The function host quietly skips triggers it can't initialize.

A quick connectivity check saves you the debugging:

docker compose exec functions curl -s http://azurite:10000

Enter fullscreen mode Exit fullscreen mode

If Azurite is reachable and bound correctly, you get back a short XML or text response. If you get "Connection refused," check the bind flags. If you get a DNS error, check your service name.

Part 1 already showed the working Compose file with these settings in place. That is why each piece is there.

Pitfall 3: Debugging a Silent Container

Your container starts, the health check passes, but nothing happens. No HTTP responses, no queue processing, no timer triggers. The logs show the host booting and then silence. This is the most common failure mode with Azure Functions in Docker, and it has six distinct causes. Work through them in order.

Debug decision tree: 6-step diagnostic flow for silent Azure Functions containers

Step 1: Check if the host found your functions. Run docker logs <container> and look for the function discovery block near startup:

Host initialized (348ms)
Found the following functions:
  ProcessOrder: timerTrigger
  SubmitOrder: httpTrigger

Enter fullscreen mode Exit fullscreen mode

If you see "Host initialized" but zero functions listed, your AzureWebJobsScriptRoot is wrong or your Dockerfile's WORKDIR does not point to /home/site/wwwroot. The host scans that directory for compiled function metadata. If it points somewhere else, it finds nothing and starts successfully with nothing to run. This is the root cause in #642 and #980.

Step 2: Check storage connectivity. If your functions are listed but triggers never fire, the problem is almost always storage. Look for this error in the logs:

The Azure Storage connection string named 'Storage' does not exist.

Timer triggers and queue triggers need a valid AzureWebJobsStorage connection to coordinate leases and checkpoints. HTTP triggers work without storage, so a container that responds to HTTP but ignores everything else is a storage configuration problem. Verify your environment variables:

docker compose exec functions env | grep FUNCTIONS

Enter fullscreen mode Exit fullscreen mode

This surfaces FUNCTIONS_WORKER_RUNTIME, AzureWebJobsStorage, and any other Functions-specific configuration in the running container.

Step 3: Inspect the container filesystem. When functions still do not appear after fixing the script root, the published output may not be where you think it is. Check directly:

docker compose exec functions ls /home/site/wwwroot

Enter fullscreen mode Exit fullscreen mode

You should see your .dll files, host.json, function.json files, and the worker.config.json. A wrong COPY --from=build path in a multi-stage Dockerfile is the most common cause: the build stage publishes to /app/publish but the copy targets /app/out, and the container starts with an empty wwwroot.

Step 4: Check for assembly conflicts. If the host discovers your functions but the worker crashes on invocation, look for FileNotFoundException referencing assemblies like System.Memory.Data. This happens when in-process WebJobs SDK packages ship inside an isolated worker image. The host and worker expect different assembly versions, and the loader fails silently until a trigger actually fires. Pin your NuGet package versions to match the host's expectations. See #1221 for the specific version matrix.

Step 5: Attach a debugger. When the logs tell you nothing useful, attach directly. VS Code's pipeTransport configuration or Rider's Docker attach both work. The critical detail: the Functions host and the isolated worker are separate .NET processes. The host is the parent process managing triggers; your code runs in the worker. Attach to the worker PID, not the host PID. If you attach to the host, you will see trigger infrastructure but none of your breakpoints will hit.

Step 6: Watch for broken image tags. Sometimes your container worked yesterday and fails today with no code changes. Base image tag updates can silently break functions. Tag 4.33.2 broke function discovery for days before anyone traced it back to the image itself (#1068). Always pin specific version tags in your Dockerfile. Never use :latest for the Functions base image in production.

Other Known Issues

A few problems fall outside the decision tree but will bite you eventually:

No graceful shutdown. The default entrypoint start.sh runs as PID 1 and does not forward SIGTERM to child processes. Your container gets SIGKILL after the orchestrator's grace period expires, which means in-flight executions are terminated without cleanup. This has been open for five years (#404). Workaround: use dumb-init or a custom entrypoint that traps signals.

Non-root containers break startup. The Functions host needs write access to /azure-functions-host at startup. Running the container as a non-root user fails unless you fix directory permissions in your Dockerfile (#424).

Development environment restart loops. Setting AZURE_FUNCTIONS_ENVIRONMENT=Development can trigger the host to restart repeatedly as it watches for file changes that never settle (#1207). Use Production or Staging in Docker unless you specifically need development-mode diagnostics.

Pitfall 4: Image Size and Cold Start

The default Azure Functions base image is 800-900 MB. Add your application code, NuGet packages, and assets, and you're over 1 GB before your first request arrives (#236).

The -slim tags can paradoxically be larger than the regular tags (#1230). Always verify with docker images.

Old extension bundles (v2 and v3) still ship inside the v4 images, wasting roughly 429 MB on code your app will never execute (#880).

Every optimization here is measurable. Start with docker images and track the delta.

Docker image layers: before (~1 GB+) vs after (~300-400 MB) optimization

.dockerignore

Without a .dockerignore, COPY . . sends your entire working directory to the Docker daemon, including .git/ history and local.settings.json (which contains connection strings and keys).

bin/
obj/
.git/
.vs/
.vscode/
local.settings.json
node_modules/
*.user
Dockerfile

Enter fullscreen mode Exit fullscreen mode

This alone can cut your build context by hundreds of megabytes and prevent secrets from leaking into image layers.

Layer ordering for cache hits

The order of your COPY instructions determines whether Docker can reuse cached layers. Copy the project file first, restore, then copy everything else:

COPY MyFunctionApp.csproj .
RUN dotnet restore

COPY . .
RUN dotnet publish -c Release -o /home/site/wwwroot

Enter fullscreen mode Exit fullscreen mode

When only source code changes, the restore layer stays cached:

Step 3/7 : RUN dotnet restore
 ---> Using cache
 ---> 4a8b2c1d3e5f
Step 4/7 : COPY . .
 ---> 9f1e2d3c4b5a

Enter fullscreen mode Exit fullscreen mode

That "Using cache" line saves 30-120 seconds per build depending on your package count. Without this ordering, every code change re-downloads every NuGet package.

ReadyToRun compilation

Add the PublishReadyToRun flag to pre-compile IL to native code, reducing JIT time at startup:

RUN dotnet publish -c Release -o /home/site/wwwroot \
    -p:PublishReadyToRun=true

Enter fullscreen mode Exit fullscreen mode

This increases image size slightly but cuts cold start latency by front-loading compilation to build time instead of request time.

Trimming (PublishTrimmed=true) is the more aggressive option. It strips unused assemblies and can dramatically reduce image size. But the Functions runtime uses reflection to discover your function endpoints, and the trimmer can remove types it considers unreachable. If your functions disappear after trimming, that's why. Use trimming only if you're willing to maintain trim annotations and test thoroughly.

Cold start: the numbers that matter

On Azure Container Apps, image pull time dominates cold start because the platform scales to zero:

Image size Pull time Total cold start
~480 MB ~20s ~25-30s
~140 MB ~7s ~12-15s

That 13-second pull difference hits every scale-from-zero event. On Functions Premium with always-ready instances, the image is cached on warm infrastructure, so size matters less for latency. It still matters for deployment speed and registry costs.

CVE accumulation

Base images are only rebuilt monthly, so vulnerabilities accumulate between rebuilds (#1185). A multi-stage build where you copy your published output onto a fresh OS base gives you control over patching:

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
# ... build steps ...

FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0
COPY --from=build /home/site/wwwroot /home/site/wwwroot

Enter fullscreen mode Exit fullscreen mode

Run docker images after applying these changes. A starting point of 1 GB+ dropping to 300-400 MB is typical when you combine layer optimization, proper .dockerignore, and ReadyToRun instead of carrying dead extension bundles.

Pre-Deploy Checklist

Save yourself a repeat debugging session. Run through this before every container deployment.

  • [ ] FUNCTIONS_WORKER_RUNTIME set to dotnet-isolated in your container environment, not inherited from local.settings.json
  • [ ] AzureWebJobsStorage uses explicit endpoint strings with Docker service names instead of UseDevelopmentStorage=true
  • [ ] Connection strings are single-line in .env files with no line-wrapping
  • [ ] docker logs confirms all expected functions discovered at startup
  • [ ] AzureWebJobsScriptRoot points to /home/site/wwwroot (verify if using a custom base image)
  • [ ] .dockerignore excludes bin/, obj/, .git/, and local.settings.json
  • [ ] NuGet restore layer cached separately from the source code copy step
  • [ ] Base image tag pinned to a specific version, not :latest
  • [ ] Azurite bound to 0.0.0.0 in your Compose configuration
  • [ ] Image tested with docker compose up locally before pushing to any registry

Which of these four pitfalls cost you the most debugging time: environment variables, Azurite networking, silent startup failures, or image size?


Azure Functions Beyond the Basics