In this episode, we'll discuss the modern replacement for ReplicationController called ReplicaSet. We'll learn about set-based selectors, matchLabels, matchExpressions, and how ReplicaSet is used by Deployments.

Note
If you want to read the previous episode, you can click the Episode 11 thumbnail below
In the previous episode, we learned about ReplicationController, the legacy controller for managing Pod replicas. In episode 12, we'll discuss the modern replacement: ReplicaSet.
Note: Here I'll be using a Kubernetes Cluster installed through K3s.
ReplicaSet is the next-generation ReplicationController with more flexible selector support. While you can use ReplicaSet directly, it's typically used as the underlying mechanism for Deployments, which provide additional features like rolling updates and rollback capabilities.
A ReplicaSet ensures that a specified number of Pod replicas are running at any given time. It's the successor to ReplicationController and provides the same core functionality with enhanced selector capabilities.
Key features of ReplicaSet:
matchLabels and matchExpressionsThe main difference between ReplicaSet and ReplicationController is the selector support:
ReplicationController - Equality-based selectors only:
selector:
app: nginx
tier: frontendReplicaSet - Set-based selectors with more flexibility:
selector:
matchLabels:
app: nginx
matchExpressions:
- key: tier
operator: In
values:
- frontend
- backendReplicaSet provides several advantages over ReplicationController:
apps/v1 API groupImportant
Best Practice: While you can use ReplicaSet directly, it's recommended to use Deployment instead. Deployments manage ReplicaSets and provide additional features like rolling updates, rollback, and declarative updates.
A ReplicaSet consists of three main components:
The number of Pod replicas you want to run:
spec:
replicas: 3Labels used to identify which Pods the ReplicaSet manages. ReplicaSet supports two types:
matchLabels - Equality-based matching:
selector:
matchLabels:
app: nginx
environment: productionmatchExpressions - Set-based matching:
selector:
matchExpressions:
- key: tier
operator: In
values:
- frontend
- backendThe template used to create new Pods:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25Let's create a basic ReplicaSet:
Create a file named replicaset-basic.yml:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-replicaset
labels:
app: nginx
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
app: nginx
tier: frontend
template:
metadata:
labels:
app: nginx
tier: frontend
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80Important
Important: The labels in the Pod template must match the selector. If they don't match, the ReplicaSet will fail to create.
Apply the configuration:
sudo kubectl apply -f replicaset-basic.ymlVerify the ReplicaSet is created:
sudo kubectl get replicasetOr use the shorthand:
sudo kubectl get rsOutput:
NAME DESIRED CURRENT READY AGE
nginx-replicaset 3 3 3 30sCheck the Pods:
sudo kubectl get podsOutput:
NAME READY STATUS RESTARTS AGE
nginx-replicaset-abc12 1/1 Running 0 30s
nginx-replicaset-def34 1/1 Running 0 30s
nginx-replicaset-ghi56 1/1 Running 0 30sReplicaSet's most powerful feature is set-based selectors using matchExpressions. Let's explore the operators:
Selects Pods where the label value is in the specified set:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: web-app-rs
spec:
replicas: 3
selector:
matchExpressions:
- key: environment
operator: In
values:
- production
- staging
template:
metadata:
labels:
app: web-app
environment: production
spec:
containers:
- name: web-app
image: nginx:1.25This ReplicaSet manages Pods with environment: production OR environment: staging.
Selects Pods where the label value is NOT in the specified set:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: non-dev-rs
spec:
replicas: 2
selector:
matchExpressions:
- key: environment
operator: NotIn
values:
- development
template:
metadata:
labels:
app: myapp
environment: production
spec:
containers:
- name: myapp
image: nginx:1.25This ReplicaSet manages Pods where environment is NOT development.
Selects Pods that have the specified label key (regardless of value):
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: labeled-rs
spec:
replicas: 2
selector:
matchExpressions:
- key: tier
operator: Exists
template:
metadata:
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: nginx:1.25This ReplicaSet manages Pods that have the tier label, regardless of its value.
Selects Pods that do NOT have the specified label key:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: unlabeled-rs
spec:
replicas: 2
selector:
matchExpressions:
- key: deprecated
operator: DoesNotExist
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: nginx:1.25This ReplicaSet manages Pods that do NOT have the deprecated label.
You can combine both for more complex selection:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: complex-selector-rs
spec:
replicas: 3
selector:
matchLabels:
app: web-app
matchExpressions:
- key: environment
operator: In
values:
- production
- staging
- key: tier
operator: NotIn
values:
- deprecated
template:
metadata:
labels:
app: web-app
environment: production
tier: frontend
spec:
containers:
- name: web-app
image: nginx:1.25This ReplicaSet selects Pods that:
app: web-app (matchLabels)environment as either production or stagingtier: deprecatedTo see detailed information about a ReplicaSet:
sudo kubectl describe rs nginx-replicasetOutput:
Name: nginx-replicaset
Namespace: default
Selector: app=nginx,tier=frontend
Labels: app=nginx
tier=frontend
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
tier=frontend
Containers:
nginx:
Image: nginx:1.25
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 2m replicaset-controller Created pod: nginx-replicaset-abc12
Normal SuccessfulCreate 2m replicaset-controller Created pod: nginx-replicaset-def34
Normal SuccessfulCreate 2m replicaset-controller Created pod: nginx-replicaset-ghi56ReplicaSet automatically replaces failed Pods, just like ReplicationController:
sudo kubectl get pods -l app=nginxsudo kubectl delete pod nginx-replicaset-abc12sudo kubectl get pods -l app=nginx -wYou'll see the ReplicaSet immediately creates a new Pod to maintain the desired count.
Scaling ReplicaSet works the same as ReplicationController:
# Scale up to 5 replicas
sudo kubectl scale rs nginx-replicaset --replicas=5
# Scale down to 2 replicas
sudo kubectl scale rs nginx-replicaset --replicas=2sudo kubectl edit rs nginx-replicasetChange the replicas field and save.
Update your YAML file and apply:
sudo kubectl apply -f replicaset-basic.ymlapiVersion: apps/v1
kind: ReplicaSet
metadata:
name: web-app-rs
labels:
app: web-app
tier: frontend
spec:
replicas: 5
selector:
matchLabels:
app: web-app
tier: frontend
template:
metadata:
labels:
app: web-app
tier: frontend
spec:
containers:
- name: web-app
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: multi-env-rs
spec:
replicas: 4
selector:
matchLabels:
app: myapp
matchExpressions:
- key: environment
operator: In
values:
- production
- staging
- key: version
operator: Exists
template:
metadata:
labels:
app: myapp
environment: production
version: v2.0
spec:
containers:
- name: myapp
image: nginx:1.25
env:
- name: ENVIRONMENT
value: "production"
- name: VERSION
value: "v2.0"apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: affinity-rs
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: myapp
image: nginx:1.25This ReplicaSet schedules Pods only on nodes with disktype: ssd label.
In practice, you rarely create ReplicaSets directly. Instead, you create Deployments, which manage ReplicaSets for you.
When you create a Deployment:
Example Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25When you apply this Deployment:
sudo kubectl apply -f deployment-example.ymlCheck the ReplicaSet created by the Deployment:
sudo kubectl get rsOutput:
NAME DESIRED CURRENT READY AGE
nginx-deployment-5d59d67564 3 3 3 30sThe ReplicaSet name includes the Deployment name and a hash.
Deployments provide additional features:
Tip
Recommendation: Always use Deployment for stateless applications instead of creating ReplicaSets directly. Use ReplicaSet only when you need fine-grained control or have specific requirements that Deployments don't support.
sudo kubectl delete rs nginx-replicasetThis deletes the ReplicaSet and all its Pods.
sudo kubectl delete rs nginx-replicaset --cascade=orphanThis deletes only the ReplicaSet, leaving Pods running as orphans.
Pod template labels must match the selector:
Wrong:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: web # Doesn't match!Correct:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx # Matches!Creating ReplicaSets directly when you should use Deployments.
Solution: Use Deployment for most use cases. It manages ReplicaSets and provides rolling updates.
Creating overly complex selectors that don't match any Pods.
Solution: Start simple, test your selectors, then add complexity if needed.
Solution: Always set resource requests and limits:
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"For most use cases, use Deployments:
apiVersion: apps/v1
kind: Deployment # Use Deployment, not ReplicaSet
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25For simple equality-based selection, use matchLabels:
selector:
matchLabels:
app: nginx
tier: frontendFor complex selection logic, use matchExpressions:
selector:
matchExpressions:
- key: environment
operator: In
values:
- production
- staging
- key: deprecated
operator: DoesNotExistUse descriptive labels for better organization:
labels:
app: web-app
tier: frontend
environment: production
version: v2.0
team: platformAlways add Probes:
livenessProbe:
httpGet:
path: /healthz
port: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080Always define resource requests and limits:
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"sudo kubectl get rssudo kubectl get events --sort-by='.lastTimestamp' | grep ReplicaSetsudo kubectl get pods -l app=nginx -wsudo kubectl top pods -l app=nginxIn episode 12, we've explored ReplicaSet in Kubernetes in depth. We've learned what ReplicaSet is, how it improves upon ReplicationController, and how to use set-based selectors for flexible Pod management.
Key takeaways:
matchLabels and matchExpressionsapps/v1 API groupWhile ReplicaSet is more powerful than ReplicationController, in practice you should use Deployment for managing stateless applications. Deployments provide all the benefits of ReplicaSets plus rolling updates, rollback capabilities, and declarative update management.
Are you getting a clearer understanding of ReplicaSet in Kubernetes? In the next episode 13, we'll discuss DaemonSet, a different type of controller that ensures a Pod runs on every node in your cluster. Keep your learning momentum going and look forward to the next episode!