Environment Variables in Kubernetes Pods: Giving Containers Their Settings
A beginner-friendly guide to how Kubernetes hands settings, secrets, and self-knowledge to your containers at startup, where each value comes from, who wins when names clash, and what can go wrong.
Imagine a new chef joining a restaurant chain. The cooking skills are the same in every branch, but each branch has different details: the address of the local supplier, the opening hours, the name of the manager, the size of the oven. Nobody rewrites the chef’s training manual for each branch. Instead, on the first morning, the chef receives a small card with the local details. Kubernetes does the same thing for software. Your container image holds the skills, and environment variables are the small card of local details handed over the moment the container starts.
1What Is an Environment Variable?
Before Kubernetes, let us understand the plain idea on a single computer.
A Named Note Pinned to a Program
An environment variable is a simple pair made of a name and a value. The name might be something like LOG_LEVEL and the value might be the word debug. When a program starts, the operating system pins a bundle of these pairs next to it. The program can read any pair by asking for its name. That is all there is to it: a name, a value, and a program that can look them up.
Think of a sticky note on the door of a hotel room. It says “Wi-Fi password: sunshine” and “Breakfast: 7 to 10”. The room itself is the same in every hotel, but the sticky note gives the details that belong to this specific stay. Environment variables are sticky notes attached to a running program.
Why Programs Love Them
Programmers use environment variables because they keep settings outside the code. The same program can behave differently in a test setup and in a real customer setup, without changing a single line of the program itself. That idea, keeping configuration separate from code, is one of the most important habits in modern software.
Environment variables always arrive as plain text. A number like 8080 or a yes-or-no like true is still just a piece of text. The program must convert it into a number or a true-or-false value itself.
2Why Kubernetes Leans on Them
Containers are meant to be identical everywhere, so their differences must come from outside.
One Image, Many Places
A container image is a sealed package holding your application and everything it needs. Teams build the image once, then run the very same image in a developer test area, a staging area, and the real production area. If settings were baked into the image, each place would need its own separate image, and nobody could be sure that what was tested is what actually runs in production.
Kubernetes solves this by letting you describe the settings separately, in the Pod description, and injecting them as environment variables when the container starts. The image never changes. Only the sticky note changes.
A school uniform is the same for all students, but each student wears a name badge. You do not sew a different uniform for each child. You just clip on a different badge. The image is the uniform, and the environment variables are the badge.
A Well-Known Recipe
This approach follows a famous set of guidelines for building cloud applications, often called the twelve-factor method. One of its rules says that anything that changes between environments should live in the environment, not in the code. Kubernetes was designed with that rule in mind, which is why environment variables are so deeply supported.
3Core Building Blocks You Must Know
Eight small terms carry almost the entire story.
Pod
The smallest running unit in Kubernetes. It holds one or more containers that share a network identity.
Container
One running copy of an image. Environment variables are defined for each container separately, not for the Pod as a whole.
env entry
One named variable in a container description, whose value is either written directly or pulled from somewhere else.
ConfigMap
A Kubernetes object that stores ordinary, non-secret settings as named keys and values.
Secret
A Kubernetes object meant for sensitive values such as passwords, tokens, and keys.
Downward API
A feature that lets a container learn facts about its own Pod, such as its name, namespace, or memory limit.
envFrom
A shortcut that imports every key of a ConfigMap or Secret as variables in one go.
Image ENV
Default variables baked into the image by its builder. Kubernetes settings can override them.
The Pod is the apartment, the container is the resident, the ConfigMap is the notice board in the lobby, the Secret is the locked mailbox, and the Downward API is the resident looking at the nameplate on their own door.
Because variables belong to each container, two containers inside the same Pod can receive completely different sets of variables. Nothing is shared automatically.
4Four Ways to Fill a Variable
Every variable gets its value from exactly one of four kinds of source.
A Plain Value Written Directly
You type the name and the value right into the Pod description. Simple, visible, and perfect for harmless settings such as a log level or a feature label.
A Key from a ConfigMap
The value lives in a ConfigMap, and the container simply points to it. The same ConfigMap can serve many Pods, so one edit can affect them all after they restart.
A Key from a Secret
The value lives in a Secret. The Pod description contains only the pointer, never the sensitive value itself, which keeps it out of casual view.
A Fact About the Pod Itself
The value comes from the Pod’s own details, such as its name, its namespace, the node it landed on, its IP address, or its resource limits. Kubernetes fills these in automatically.
flowchart LR
A["Plain value in Pod description"] --> E["Container environment"]
B["ConfigMap key"] --> E
C["Secret key"] --> E
D["Pod facts from Downward API"] --> E
E --> F["Application reads variables at startup"]
5Plain Values: The Simplest Way
Sometimes the easiest note is one you write yourself.
How It Works
Inside the description of a container, you list its variables one by one. Each entry has a name and a value. When Kubernetes creates the container, it adds each pair to the environment. The application starts and finds them waiting.
When It Fits
Plain values suit settings that are not sensitive and are unique to one workload: the name of the environment, a mode switch, a timeout, or a flag. They are easy to read during review because everything is in one place.
This is like writing the opening hours directly on the shop door. Anyone who walks past can read it, and it is right where it is needed. It would be silly to write the safe combination on the same door.
Advantages
- Very easy to understand and review
- No extra objects to create or maintain
- Values travel together with the workload
- Good for small, workload-specific settings
Disadvantages / Trade-offs
- Values are visible to anyone who can read the Pod description
- Repeating the same value in many places invites mistakes
- Unsuitable for anything sensitive
- Changing a shared setting means editing many workloads
6Values from a ConfigMap
When many workloads share the same settings, keep them in one shared place.
What a ConfigMap Is
A ConfigMap is a small storage box inside the cluster for non-secret settings. Each item in the box has a key and a value. Examples include the address of an internal service, the default language of an application, or the number of items to show per page.
Pointing at One Key
In the container description, instead of writing a value, you say “take the value from this key of that ConfigMap”. At startup, Kubernetes looks up the key and places its value in the variable. You can even give the variable a different name from the key, which is handy when the application expects a specific variable name.
A company keeps a single notice board with the canteen timings. Every department refers to that board instead of writing the timings on their own walls. When the timings change, only the board is updated.
You can mark a ConfigMap reference as optional. Then, if the ConfigMap or key is missing, the container still starts and the variable is simply absent. Without that mark, a missing reference stops the container from starting at all.
Editing a ConfigMap and expecting running containers to notice. Variables are read once at startup. The running container keeps its old values until it is restarted.
7Values from a Secret
For passwords and tokens, Kubernetes offers a separate box with extra care around it.
What a Secret Is
A Secret is an object designed to hold sensitive values, like database passwords, access tokens, or private keys. It looks similar to a ConfigMap, but the cluster treats it more carefully. Access to it can be limited with permission rules, and it can be encrypted when stored.
Referencing It Safely
Just as with a ConfigMap, the container says “take this variable’s value from that key of that Secret”. The Pod description contains only the pointer. Someone reading the description sees the name of the Secret, not the password inside.
Think of a hotel staff card that says “safe number 12, ask the manager”. The card never shows the safe’s code. Only someone with the right permission can open the safe and read what is inside.
Secret values are stored in a scrambled-looking format called base64, but that is only an encoding, not protection. Anyone who can read the Secret can decode it in seconds. Real protection comes from permission rules and encryption at rest.
The Catch with Variables
Once a secret value becomes an environment variable, it lives inside the running process. It can show up in crash reports, in debugging tools, or be inherited by any child program the application starts. This is why many teams prefer to deliver especially sensitive values as files instead, which Chapter 14 explains.
8Pod Self-Knowledge: The Downward API
Sometimes a container needs to know who it is and where it lives.
Why a Container Needs to Know
An application may want to include its Pod name in log lines so operators can trace problems. It may need to know its namespace to build a matching address, or its node name to report where it runs. It may even need to know how much memory it was given, so it can size its internal caches sensibly. None of these facts are known when the image is built, because they are decided later by Kubernetes.
Two Kinds of Facts
About the Pod
Pod name, namespace, unique ID, service account, node name, node address, Pod address, and individual labels or annotations.
About the Container
The container’s processor and memory requests and limits, optionally scaled into convenient units.
Imagine a delivery driver looking at the label on the parcel to see their own route number and truck capacity. The information comes from the system that assigned the job, not from the driver’s own memory. The Downward API is that label.
Resource limits are often given in raw bytes or fractions of a processor. The scaling option lets you request them in friendlier units, such as megabytes, so the application does not need extra conversion logic.
Reading a limit variable when no limit was set. In that case Kubernetes reports the node’s capacity instead, which can be far larger than what the application should use. Always set explicit limits when applications depend on these values.
9Bulk Import with envFrom
When a ConfigMap has twenty keys, listing them one by one gets tiring.
Import Everything at Once
The envFrom feature tells Kubernetes: “take every key of this ConfigMap or Secret and turn each into a variable”. The key names become the variable names, and the values become the variable values. One line does the work of twenty.
Adding a Prefix
You can add a prefix that is stuck in front of every imported name. This is very useful when importing from several sources, because it prevents two sources from accidentally using the same variable name.
Moving into a new house, you can carry boxes one item at a time, or you can say “bring the whole box of kitchen things”. Adding a prefix is like writing “KITCHEN” on every item so they never get mixed with the bathroom items.
Advantages
- Much shorter Pod descriptions
- New keys appear after the next restart without editing the Pod
- Prefixes prevent name clashes between sources
- Works for both ConfigMaps and Secrets
Disadvantages / Trade-offs
- Hard to see at a glance exactly which variables exist
- Keys that are not valid variable names are skipped, sometimes silently
- Unwanted keys come along for the ride
- Accidentally importing a whole Secret exposes more than needed
Assuming every key becomes a variable. Keys containing characters such as dashes or dots may not form valid variable names, so they are skipped. The container starts fine, but the variable is missing, and only an event in the Pod’s history hints at why.
10Who Wins? The Rules of Precedence
When two sources define the same name, exactly one value survives.
The Layers
A container’s final environment is built in layers. At the bottom are the defaults baked into the image. On top of that come variables imported in bulk. On top of those come the individually listed variables. When the same name appears in more than one layer, the higher layer wins.
Image Defaults
The lowest layer. Values set by whoever built the image. Easily overridden by anything Kubernetes provides.
envFrom Sources
Bulk imports are applied in the order listed. If two imported sources share a name, the later one in the list wins.
Individually Listed Variables
Entries in the explicit list override anything imported in bulk under the same name. This is the top layer.
flowchart TD
A["Image default value"] --> B["envFrom first source"]
B --> C["envFrom later source"]
C --> D["Explicit env entry"]
D --> E["Final value seen by the application"]
Think of painting a wall. The first coat is the factory default. Each new coat covers the previous one where they overlap. The last coat applied is the colour you see.
Use the explicit list for deliberate overrides, and keep bulk imports for broad defaults. That way anyone reading the Pod description can immediately see which values were intentionally forced.
11Variables That Refer to Other Variables
Kubernetes has a small built-in trick for combining values.
Building One Value from Others
Inside a variable’s value or inside a container’s start command and arguments, you can refer to another variable by wrapping its name in a special reference form. Kubernetes replaces the reference with the actual value before the container starts. This lets you assemble a full address from smaller parts, like a host and a port.
The Rules That Trip People Up
Only Earlier Variables Count
A reference works only if the variable it points to is defined earlier in the list. A reference to a variable defined later stays as plain text.
The Same Trick Works in Commands
Start commands and arguments can use the same reference form. This is different from a shell expanding a dollar sign, because Kubernetes does it before any shell runs.
Escaping Is Possible
If you truly want the literal text instead of a substitution, doubling the leading dollar sign turns the substitution off.
It is like a form letter that says “Dear [Name], your order [Number] is ready”. The printing system fills the gaps before the letter is sent. If the number field has not been prepared yet, the gap stays blank or unchanged.
Listing variables in the wrong order and then wondering why the combined value looks broken. Always define the ingredients before the recipe that uses them.
12Automatic Service Variables
Kubernetes quietly adds some variables you never asked for.
The Old Way of Finding Services
When a Pod starts, Kubernetes looks at the Services that already exist in the same namespace and adds variables describing each one: its address and its port. The variable names are built from the Service name, in capital letters with underscores. This was one of the earliest ways for applications to discover each other.
The Ordering Problem
There is a big catch. These variables are created only for Services that exist at the moment the Pod starts. If a Service is created afterwards, existing Pods never receive its variables. That forces teams to create Services before the Pods that need them, which is fragile and easy to forget.
It is like printing a phone directory once and handing it to a new employee. Anyone who joins the company after the printing is not in the book, and the employee’s copy is never updated.
| Aspect | Service Variables | DNS Names |
|---|---|---|
| When filled | Once, at container start | Live, at every lookup |
| Sees new Services | No, not without a restart | Yes, almost immediately |
| Creation order matters | Yes, Service first | No |
| Crosses namespaces | No, same namespace only | Yes, with the namespace in the name |
| Environment clutter | Adds many variables | Adds none |
Modern practice is to use DNS names for discovery. If your Pods do not need the automatic Service variables, you can switch them off for a Pod. This also helps in namespaces with very many Services, where the sheer number of variables can bloat the environment.
13When Are Values Actually Read?
This single fact explains most surprises about environment variables in Kubernetes.
The Snapshot Moment
Variables are collected just before a container starts, and then frozen. The values are copied into the new process. From that moment, the process holds its own private copy. If the source ConfigMap or Secret is edited later, the running container is not told and its copy does not change.
sequenceDiagram
participant U as You
participant K as Kubelet
participant A as API Server
participant C as Container
U->>A: Create Pod with variable sources
K->>A: Read Pod description
K->>A: Fetch ConfigMap and Secret values
A-->>K: Return current values
K->>C: Start process with a frozen copy
Note over C: Values never change while it runs
U->>A: Edit the ConfigMap later
Note over C: Running container still holds the old copy
U->>A: Trigger a rollout
K->>C: Start a new container with fresh values
It is like photocopying a page from a reference book before going into an exam. If the book is corrected tomorrow, your photocopy stays exactly as it was. To get the corrected version, you must make a new photocopy.
How Teams Handle Changes
To apply a changed setting, teams trigger a rolling restart, which replaces Pods gradually so the application stays available. Many teams make the ConfigMap name include a fingerprint of its contents, so any content change produces a new name, which automatically changes the Pod description and starts a rollout. Some teams also run small controllers that watch for changes and restart the affected workloads.
14Environment Variables vs Files vs Arguments
Kubernetes offers other ways to deliver settings, and each has its place.
| Delivery Method | How the App Sees It | Updates While Running? | Best For |
|---|---|---|---|
| Environment variable | A named variable in the process | No, restart needed | Small, simple settings that rarely change |
| Mounted file | A file in a folder | Often yes, after a short delay | Larger configs, certificates, and sensitive values |
| Command argument | A flag on the start command | No, restart needed | Programs that expect flags |
| Direct API read | The app asks the cluster itself | Yes, live | Advanced cases needing live data |
Why Choose Variables
- Nearly every programming language can read them
- No file handling code required
- Very easy to inspect and reason about
- Widely expected by ready-made container images
Why Choose Files Instead
- Sensitive values are less likely to leak through crash dumps and child programs
- Updates can arrive without restarting
- Better for large or structured configuration
- File permissions offer finer control
A variable is like a sticky note stuck on the person at the start of the day. A mounted file is like a folder on their desk that can be swapped for a fresh version at any time. Notes are quick and simple. Folders are better for bulky or sensitive material.
Expecting mounted files to update when they were attached in certain special ways, such as pinning a single file path. Those variants do not refresh, so test the behaviour you rely on.
15When Things Go Wrong: Failure Modes and Fixes
Most variable problems fall into a handful of familiar shapes.
Container Will Not Start: Missing Reference
The Pod is stuck with a status about a configuration error. The usual cause is a reference to a ConfigMap, Secret, or key that does not exist, or that lives in a different namespace. References only work within the same namespace as the Pod.
Variable Exists but Has the Wrong Value
Usually a precedence surprise. Another layer, such as a later bulk import or an explicit entry, overrode the value you expected. Check every layer in the order described in Chapter 10.
Variable Is Missing Entirely
Often an imported key had a name that is not a valid variable name, so it was skipped. It can also happen when a reference was marked optional and the source did not exist.
Old Value After an Edit
The ConfigMap or Secret was updated but the container was not restarted. Variables are frozen at startup, so the container still holds the previous snapshot.
Combined Value Looks Wrong
A reference to another variable stayed as plain text because that variable was defined later in the list, or because the reference form was misspelled.
A Calm Debugging Path
Read the Pod Status and Events
The Pod’s history usually names the exact missing object or skipped key. Start here before guessing.
Confirm the Sources Exist
Check that the ConfigMap or Secret exists in the same namespace, and that the key is spelled exactly right, including capitals.
Look Inside the Running Container
Open a session in the container and print its environment. This shows what the application truly sees, not what you hoped it would see.
Walk the Precedence Layers
List every place the variable name could be set: image defaults, bulk imports, and explicit entries. Work out which one wins.
Restart with a Rollout
If a source was changed after start, roll out new Pods so they capture the fresh values, then check again.
16Security Considerations
Environment variables are convenient, and convenience deserves careful handling.
Plain Values Are Visible
Anything written directly into a Pod description can be read by everyone who can view that Pod.
Leaks Through Logs
Applications sometimes print their whole environment during startup or when they crash, spilling secrets into log files.
Child Programs Inherit Them
Every program started by the application receives the same variables, including tools that should never see a password.
Over-Broad Bulk Imports
Importing a whole Secret gives the container every value in it, even ones it does not need.
Weak Access Rules
Anyone allowed to read a Secret or to open a session in a container can see the values.
Writing your bank PIN on a sticky note and clipping it to your shirt is convenient, but everyone you meet can read it. Convenience and secrecy pull in opposite directions, so sensitive items need a safer holder.
Practical Protections
Keep sensitive values in Secrets, never as plain values in the Pod description. Restrict who can read Secrets and who can enter running containers, using role-based permissions. Turn on encryption at rest for Secrets. Reference only the specific keys a container needs instead of importing entire Secrets. Prefer mounting truly sensitive values as files with tight permissions. Consider external secret managers that fetch values from a dedicated vault. Finally, make sure applications never print their whole environment, and scrub logs of anything that looks like a credential.
Committing Secret definitions with real values into a shared code repository. The scrambled base64 form fools people into feeling safe, but it is trivially reversible.
17Monitoring, Logging, and Auditing
You cannot fix what you cannot see, and configuration problems are often invisible until they hurt.
What to Watch
Configuration mistakes usually announce themselves through the Pod’s lifecycle rather than through application metrics. The most useful signals are container start failures, repeated restarts, and events mentioning missing or skipped configuration. Alerts on Pods stuck in a waiting state because of configuration errors catch many problems minutes after a deployment.
Logging with Care
Have applications log which configuration profile they loaded, but never the values of sensitive settings. A safe habit is to log the names of settings and whether they were found, without printing the values. That gives operators enough to diagnose a problem while keeping secrets out of log storage.
Auditing Changes
Who changed a ConfigMap, and when? Cluster audit logs can answer this, and storing configuration in version control gives a reviewable history. Because a small change to a shared ConfigMap can affect many workloads after their next restart, treat those changes with the same care as code changes.
A restaurant manager checks that every kitchen received today’s menu card, but never reads out the safe combination on the loudspeaker. Confirm the cards arrived, without exposing the secrets.
18Design Patterns and Anti-Patterns
Good habits keep configuration boring, and boring is exactly what you want.
Pattern: One Image, Environment-Specific Settings
Build the image once and supply everything that differs, such as addresses and modes, through variables at deployment time.
Pattern: Names That Say Their Purpose
Use clear, consistently formatted variable names, often with a short application prefix. This makes bulk imports safe and logs easy to read.
Pattern: Split Non-Secret and Secret Sources
Keep ordinary settings in ConfigMaps and sensitive ones in Secrets, so access permissions can differ and reviews are simpler.
Pattern: Self-Aware Applications
Use the Downward API so applications add their Pod name and namespace to logs and metrics, making troubleshooting far faster.
Pattern: Content-Fingerprinted Configuration
Generate ConfigMap names from their contents so that any change automatically triggers a controlled rollout.
Problem
Passwords and tokens are written directly as plain values in the Pod description.
Why It’s Harmful
Anyone who can view the Pod, or the file it came from, can read the credentials. They also end up in version history.
Correct Approach
Store sensitive values in Secrets or an external secret manager and reference them, or mount them as files.
Problem
Editing a shared ConfigMap and assuming every application has instantly adopted the change.
Why It’s Harmful
Running containers keep old values, so different Pods behave differently until they restart at random times, causing puzzling, inconsistent behaviour.
Correct Approach
Follow every configuration change with a planned rollout, or use fingerprinted names so the rollout happens automatically.
Problem
Importing huge ConfigMaps or Secrets in bulk without knowing what they contain.
Why It’s Harmful
Unneeded and sensitive values reach containers that should never see them, and unexpected name clashes silently change behaviour.
Correct Approach
Import small, purpose-built sources, use prefixes, and reference individual keys for sensitive data.
19Best Practices and Common Mistakes
A short checklist that prevents most variable trouble before it starts.
Best Practices
- Keep configuration out of images and inside Pod descriptions or shared sources
- Use Secrets for anything sensitive, and limit who can read them
- Choose descriptive, consistent, capitalised variable names
- Use immutable ConfigMaps and Secrets where possible, to avoid surprise edits
- Set explicit resource limits when reading them through the Downward API
- Validate required variables at application startup and fail loudly if missing
Common Mistakes
- Expecting running containers to notice edited sources
- Using a reference across namespaces
- Forgetting that every value is text, not a number or boolean
- Defining combined variables before their ingredients
- Printing the entire environment in logs
- Marking references optional and never noticing they are absent
Make your application check its own required variables at startup and refuse to run if one is missing. A loud early failure is far cheaper than a quiet wrong behaviour discovered at midnight.
20Real-World Examples
Here is how variables quietly power everyday cluster designs.
One Web Application, Three Environments
A team builds one image of its shopping site. The test area points it at a test database and enables detailed logging. The production area points it at the real database with quiet logging. Only variables differ, so what was tested is exactly what runs.
Database Credentials for a Payments Service
A payments service receives its database user and password from a Secret managed by a dedicated security team. Developers can deploy the service but cannot read the password, because permissions separate the two roles.
Log Lines That Say Where They Came From
Every container gets its Pod name, namespace, and node name through the Downward API. When an error appears in a central log system, engineers instantly know which Pod and node produced it.
Right-Sizing a Java Application
A Java service reads its memory limit through the Downward API and sets its internal memory pool to a fraction of it. The same image then behaves sensibly whether it runs with a small or a large allocation.
Feature Switches per Customer Region
A company runs the same application in several regions. Each region has its own ConfigMap toggling regional features and currencies. Turning on a feature for one region is a small, reviewable change followed by a controlled rollout.
21Frequently Asked Questions
Per container. Each container in a Pod has its own list, and one container never automatically sees another container’s variables.
Not in a supported way. Variables are fixed when the container starts. To apply a change, replace the Pod, usually through a rolling restart of its parent workload.
By default the container will not start, and the Pod shows a configuration error. If the reference is marked optional, the container starts and the variable is simply absent.
The Kubernetes setting wins. Values supplied in the Pod description override defaults baked into the image.
They are handled with more care, with tighter access options and encryption possibilities. But once the value becomes a variable, it lives in the process and can leak through logs or child programs, so extra caution is still needed.
No. Variable references to ConfigMaps and Secrets must point to objects in the Pod’s own namespace.
Keys whose names are not valid variable names are skipped during a bulk import. The container still starts, and an event in the Pod’s history records the skipped keys.
Yes, the operating system limits how much data can be passed to a new process, and very large environments can cause start failures. Keep variables small and move bulky data into mounted files.
Use variables for small, simple, stable settings. Prefer files for larger configuration, for certificates, for sensitive values, or when you want updates to arrive without restarting.
Rarely. DNS names are more flexible and always current. The automatic variables depend on Service creation order and are fixed at start, so most teams rely on DNS and may switch the variables off.
22Summary and Key Takeaways
Environment variables are the small card of local details that Kubernetes hands to each container at startup. They let a single, well-tested image behave correctly in many different places. Values can be written directly, pulled from a ConfigMap, pulled from a Secret, or filled in from facts about the Pod itself. Bulk imports save effort, a clear order of precedence decides which value wins, and everything is frozen at the moment the container starts. With careful handling of secrets, a habit of rolling out after every change, and clear names, this humble feature becomes one of the most reliable tools in the cluster.
Key Takeaways
- Config stays out of the image — build once, then supply the differences through variables for each environment.
- Four sources — plain values, ConfigMap keys, Secret keys, and Pod facts from the Downward API.
- Precedence is layered — image defaults are overridden by bulk imports, which are overridden by explicit entries.
- Values are frozen at start — edits to sources reach a container only after it restarts, so plan rollouts.
- Same namespace only — ConfigMap and Secret references cannot cross namespaces, and missing ones block startup unless marked optional.
- Secrets need real protection — base64 is not encryption; use permissions, encryption at rest, careful logging, and files for the most sensitive values.
- Prefer DNS for discovery — automatic Service variables depend on creation order and never update, so use names instead.