When you deploy workloads such as Deployments, StatefulSets, DaemonSets, Jobs, and CronJobs in a Container Service for Kubernetes (ACK) cluster, following the configurations in this topic helps keep your applications stable and resilient during real-world failures.
Declare requests and limits for each pod
Over-scheduling too many pods to a node can cause resource contention and service disruption. Declare requests and limits for each pod allows the scheduler to identify suitable nodes based on specific resource requirements during deployment..
Example Nginx pod configuration:
CPU request of 1 core and memory request of 1024 Mi
CPU limit of 2 cores and memory limit of 4096 Mi
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
resources: # Resource declaration
requests:
memory: "1024Mi"
cpu: "1000m"
limits:
memory: "4096Mi"
cpu: "2000m"Static resource scheduling
Kubernetes uses a static resource scheduling mechanism. Available node resources are calculated as:
Available node resources = Total node resources - Allocated resourcesNote that Kubernetes cannot track the actual resource consumption of resource-intensive programs run manually (outside of pod declarations). Therefore, the scheduler makes decisions based on allocated resources rather than real-time usage. If a pod has no declared resources, Kubernetes reserves nothing for it after scheduling—resulting in more pods sharing a node than its capacity supports.
How limits are enforced:
CPU limits: enforced by CPU throttling. When a container approaches its CPU limit, the kernel restricts its CPU access. The container continues running but executes more slowly.
Memory limits: enforced by the kernel with out-of-memory (OOM) kills. When a container exceeds its memory limit, the kernel terminates it.
This difference matters for how you set limits: CPU limits can be set conservatively because throttling degrades performance gracefully, while memory limits require more careful calibration because exceeding them terminates the container.
Best practice: Use resource profiling
We recommend use the Resource Profiling feature to get container-level resource recommendations based on historical usage data, simplifying the complexity of configuring requests and limits.
Wait for dependencies at startup
Applications often have external dependencies, such as databases or downstream APIs, that may not be ready when the application starts.
In traditional manual environments, a fail-fast approach makes sense: the application exits immediately if a dependency is unavailable, alerting operators that something is wrong. However, in Kubernetes, this can lead to unnecessary restart loops. Consider two applications, A and B, where A depends on B, and both are scheduled on the same node. A node reboot may cause A to start before B is ready. A exits before B becomes available—and without intervention, A may not recover even after B starts.
Instead of existing, applications running in Kubernetes should gracefully wait for their dependencies. We recommend using an Init Container to poll for required services: the Init Container blocks the main container from starting until all dependencies are reachable.
Configure the restart policy
Processes can exit for many reasons—bugs, OOM events, or transient errors. Configure a restartPolicy so the kubelet automatically recovers the pod without manual intervention.
apiVersion: v1
kind: Pod
metadata:
name: nginx-test
spec:
restartPolicy: OnFailure
containers:
- name: nginx
image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6restartPolicy accepts one of the following values:
Value | Behavior |
| Restarts the container whenever it exits |
| Restarts the container only if it exits with a non-zero status code |
| Does not restart the container |
Configure health check probes
Health check probes give Kubernetes the information it needs to automatically recover from failures and route traffic only to ready instances. Three probe types work together:
startupProbe: checks whether the application has finished starting. Until this probe succeeds, the kubelet does not runreadinessProbeorlivenessProbe. UsestartupProbewhen startup time is unpredictable (for example, Java applications that perform class loading or database migrations). If your application always starts within a fixed window, setinitialDelaySecondson the other probes instead.readinessProbe: controls traffic routing. A pod's IP is added to the service endpoints only after this probe succeeds, ensuring that requests reach only containers that are ready to handle them.livenessProbe: detects deadlocks and crashes where the process is still running but the application is unresponsive. On failure, the kubelet restarts the container.ImportantOnly use
livenessProbeto check the health of the application itself. Never depend on external resources, such as a database, because this can trigger cascading restarts during external outages.
Choosing probe parameters:
Design startupProbe and livenessProbe thresholds around the maximum time you want to tolerate before Kubernetes acts:
Maximum tolerated time = failureThreshold × periodSecondsFor livenessProbe, use a higher failureThreshold than readinessProbe. This ensures the pod is marked not-ready for a period before the kubelet performs a hard restart, giving you a window to observe the issue.
The following example configures all three probes for a stateless Nginx Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-demo
spec:
replicas: 1 # For production environments, set this to 2 or more to ensure high availability
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- name: nginx
image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
ports:
- containerPort: 80
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 500m
# --- Health check probes ---
# Startup Probe: Ensures the application in the container has started.
startupProbe:
httpGet:
path: / # Accessing the Nginx default root path indicates a successful startup.
port: 80
# Allow enough time for the application to start. Total timeout = failureThreshold x periodSeconds, which is 30 x 10 = 300 seconds.
failureThreshold: 30
periodSeconds: 10
# Readiness Probe: Determines if the container is ready to accept traffic.
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5 # Starts probing 5 seconds after the container starts.
periodSeconds: 5 # Probes every 5 seconds.
timeoutSeconds: 2 # Probe timeout.
successThreshold: 1 # 1 success marks it as ready.
failureThreshold: 3 # 3 consecutive failures mark it as not ready.
# Liveness Probe: Determines if the container is alive for automatic fault recovery.
# This configuration should be looser than the readinessProbe to avoid unnecessary restarts due to temporary jitter.
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 15 # Starts the first probe 15 seconds after the container starts, allowing the application to initialize and stabilize.
periodSeconds: 10 # The probe frequency is lower than the readinessProbe to reduce system resource consumption.
timeoutSeconds: 3 # The timeout can be slightly longer than the readinessProbe.
successThreshold: 1 # 1 success marks it as alive.
failureThreshold: 3 # After 3 consecutive failures (3 x 10 = 30 seconds), the kubelet restarts the container.See Implement zero-downtime rolling deployments for production environments.
Run one process per container
Some developers treat containers like virtual machines and run multiple processes—monitoring agents, logging daemons, sshd—inside a single container. This creates two problems:
Resource accounting becomes unreliable. With multiple processes sharing a container, it is harder to set accurate
requestsandlimits, which leads to either over-provisioning or resource contention.Failures go undetected. When a container runs a single process, the container engine immediately knows if that process exits and can restart the container. When multiple processes run together, the container engine cannot detect if one of them crashes silently.
When multiple processes genuinely need to work together—for example, Nginx and PHP-FPM communicating through a Unix Domain Socket—put each process in its own container and run them as a multi-container pod. Store the Unix Domain Socket in a volume shared between the containers.
Avoid single points of failure
A single pod instance represents a single point of failure. Even with automatic restarts, there is a brief interruption during the recovery process. Similar downtime can also occur during rolling updates or new version releases.
To ensure high availability, avoid managing Pods directly. Instead, manage your workloads through Deployments or StatefulSets and ensure at least two replicas are running at all times. This redundancy allows Kubernetes to maintain service continuity even if an individual instance fails.
What's next
ACK supports phased releases, blue-green deployments, and other release strategies. For details, see Deployment and release.
For broader application management guidance, see Workload best practices.
If a pod is behaving unexpectedly, see Troubleshoot pod exceptions. For common questions, see Workload FAQ.