Extending Kubernetes Quiz
This quiz tests your conceptual and practical knowledge about Kubernetes extension mechanisms. It covers topics such as Custom Resource Definitions (CRD), custom controllers, API extensions, webhooks, and the operator pattern.
Multiple Choice Questions
- What is the most common way to define custom resources in Kubernetes?
- A) Define resource schema using ConfigMap
- B) Create a CustomResourceDefinition (CRD)
- C) Directly modify API server code
- D) Use the Aggregation Layer
Show Answer
Answer: B) Create a CustomResourceDefinition (CRD)
Explanation: The most common way to define custom resources in Kubernetes is to create a CustomResourceDefinition (CRD). CRD is a mechanism that allows you to extend the Kubernetes API by defining new resource types.
Using CRDs provides the following benefits:
- You can add new resource types without modifying the existing Kubernetes API server.
- You can manage custom resources using standard Kubernetes tools like
kubectl. - You can leverage features such as resource validation, versioning, and status subresources.
CRD example:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
cronSpec:
type: string
image:
type: string
replicas:
type: integer
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ctIssues with other options:
- ConfigMaps are used to store configuration data and are not suitable for API extensions.
- Directly modifying API server code is complex, difficult to maintain, and can cause issues during upgrades.
- The Aggregation Layer is another way to define custom resources, but it's more complex than CRDs since it requires implementing a separate API server.
- What is the main purpose of a Kubernetes Operator?
- A) Optimize resource usage of cluster nodes
- B) Encode operational knowledge of complex applications into automated software
- C) Improve Kubernetes API server performance
- D) Extend cluster networking functionality
Show Answer
Answer: B) Encode operational knowledge of complex applications into automated software
Explanation: The main purpose of a Kubernetes Operator is to encode operational knowledge of complex applications into automated software. The operator pattern is a software implementation of how a human operator manages complex applications.
Key characteristics of operators:
- Combines custom resources with custom controllers to implement application-specific logic.
- Automates operational tasks such as application deployment, upgrades, backup, recovery, and scaling.
- Continuously monitors application state and adjusts to the desired state.
- Codifies domain knowledge to enable declarative management of complex applications.
Common use cases for operators:
- Automated management of databases (e.g., PostgreSQL, MySQL, MongoDB)
- Deployment and configuration of messaging systems (e.g., Kafka, RabbitMQ)
- Setup and maintenance of monitoring systems (e.g., Prometheus)
- Management of service meshes (e.g., Istio)
Operator example - Prometheus Operator:
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
spec:
serviceAccountName: prometheus
replicas: 2
version: v2.35.0
serviceMonitorSelector:
matchLabels:
team: frontend
resources:
requests:
memory: 400MiWith this simple declarative configuration, the Prometheus Operator automatically handles complex tasks such as:
- Deploying Prometheus servers
- Creating and managing configuration files
- Automatic discovery of service monitoring targets
- High availability setup
- Storage management
- Upgrade coordination
Other options are not the main purpose of operators:
- Resource usage optimization is the role of HPA (Horizontal Pod Autoscaler), VPA (Vertical Pod Autoscaler), etc.
- Improving API server performance is not the main purpose of operators.
- Extending networking functionality is the role of CNI plugins or service meshes.
- What is the main function of Admission Webhooks in Kubernetes?
- A) Handle authentication for API server
- B) Intercept resource creation or modification requests to validate or modify them
- C) Monitor cluster events and send alerts
- D) Provide APIs for integration with external systems
Show Answer
Answer: B) Intercept resource creation or modification requests to validate or modify them
Explanation: The main function of Admission Webhooks in Kubernetes is to intercept resource creation or modification requests to validate or modify them. Admission webhooks provide a mechanism to intercept requests before the Kubernetes API server stores them in persistent storage (etcd).
Two types of admission webhooks:
Validating Webhook:
- Validates resource create, update, and delete requests.
- Can allow or deny requests but cannot modify them.
- Used for policy enforcement, security checks, configuration validation, etc.
Mutating Webhook:
- Can validate and modify resource create and update requests.
- Used for setting defaults, injecting sidecar containers, adding labels, etc.
- Runs before validating webhooks.
Admission webhook configuration example:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: pod-policy-validator
webhooks:
- name: pod-policy.example.com
clientConfig:
service:
namespace: webhook-namespace
name: webhook-service
path: "/validate-pods"
caBundle: <base64-encoded-ca-cert>
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
scope: "Namespaced"
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
timeoutSeconds: 5Common use cases for admission webhooks:
- Enforcing security policies (e.g., prohibiting privileged containers)
- Enforcing resource requests and limits
- Automatic injection of sidecar containers (e.g., Istio)
- Automatic addition of labels and annotations
- Restricting image registries
- Applying namespace-based policies
Issues with other options:
- Handling authentication for API server is the role of Authentication Plugins.
- Monitoring cluster events and sending alerts is the role of event listeners or monitoring tools.
- Providing APIs for integration with external systems is a general purpose of API extensions, but not the main function of admission webhooks.
- What is the main purpose of the Aggregation Layer in the Kubernetes API server?
- A) Optimize API server performance
- B) Consolidate multiple API servers into a single API server
- C) Integrate custom API servers into the main API server to extend the API
- D) Provide service discovery within the cluster
Show Answer
Answer: C) Integrate custom API servers into the main API server to extend the API
Explanation: The main purpose of the Aggregation Layer in the Kubernetes API server is to integrate custom API servers into the main API server to extend the API. This provides another way to extend the Kubernetes API, offering more powerful features than CRDs, though more complex.
Key characteristics of the Aggregation Layer:
- Integrates custom API servers into the URL space of the Kubernetes API server.
- Custom API servers can have their own storage, business logic, API versions, etc.
- The main API server proxies requests to the appropriate custom API server.
- Authentication and authorization are handled by the main API server.
Cases where the Aggregation Layer is used:
- When complex validation logic is needed
- When a custom storage backend is required
- When different behavior from existing APIs is needed
- When resource transformation or special state calculation is required
APIService resource example:
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1alpha1.metrics.k8s.io
spec:
service:
name: metrics-server
namespace: kube-system
group: metrics.k8s.io
version: v1alpha1
insecureSkipTLSVerify: true
groupPriorityMinimum: 100
versionPriority: 100This configuration routes requests for the metrics.k8s.io/v1alpha1 API group to the metrics-server service in the kube-system namespace.
Real examples using the Aggregation Layer:
- metrics-server: Provides node and pod resource usage metrics
- service-catalog: Integration with external service brokers
- custom-metrics-apiserver: Provides custom metrics for HPA
Issues with other options:
- The Aggregation Layer is not for optimizing API server performance.
- Consolidating multiple API servers into one is not an accurate description. The Aggregation Layer integrates multiple API servers into a single URL space, but the servers run separately.
- The Aggregation Layer does not provide service discovery. That is the role of Kubernetes Services.
- What is the main role of a Custom Controller in Kubernetes?
- A) Monitor resource usage of cluster nodes
- B) Observe the state of custom resources and reconcile to the desired state
- C) Handle authentication and authorization for API server requests
- D) Manage cluster networking
Show Answer
Answer: B) Observe the state of custom resources and reconcile to the desired state
Explanation: The main role of a Custom Controller in Kubernetes is to observe the state of custom resources and reconcile to the desired state. Controllers implement the "reconciliation loop," a core operational pattern in Kubernetes, to continuously adjust the system's actual state to the desired state.
Key characteristics of custom controllers:
- Watch specific resource types (typically custom resources defined via CRDs).
- React to resource change events and execute business logic.
- Perform tasks to adjust the actual state of resources to the desired state.
- Update the status field of resources to reflect the current state.
Common components of custom controllers:
- Informer: Watches the Kubernetes API server and receives resource change events.
- Work Queue: Stores and manages events to be processed.
- Reconciler: Compares the desired state and actual state of resources and performs necessary tasks.
- Client: Interacts with the Kubernetes API to create, update, and delete resources.
Custom controller example - simple reconcile function:
func (c *Controller) reconcile(key string) error {
// Split key into namespace and name
namespace, name, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
return err
}
// Get custom resource
instance, err := c.customResourceLister.CustomResources(namespace).Get(name)
if errors.IsNotFound(err) {
// Resource deleted - perform cleanup
return nil
}
if err != nil {
return err
}
// Check resource state and perform necessary tasks
// e.g., create sub-resources, integrate with external systems, update status, etc.
// Update status
instanceCopy := instance.DeepCopy()
instanceCopy.Status.Phase = "Reconciled"
_, err = c.customResourceClient.CustomResources(namespace).UpdateStatus(instanceCopy)
return err
}Common use cases for custom controllers:
- Automating complex application deployment and management
- Integration with external systems (e.g., cloud resource provisioning)
- Automating backup and recovery processes
- Implementing advanced deployment strategies (e.g., canary deployments, blue-green deployments)
Issues with other options:
- Monitoring resource usage of cluster nodes is the role of metrics-server or monitoring tools like Prometheus.
- Handling authentication and authorization for API server requests is the role of authentication and authorization plugins.
- Managing cluster networking is the role of CNI plugins or network controllers.
- What format is used to define validation schemas for CRDs (CustomResourceDefinitions) in Kubernetes?
- A) JSON Schema
- B) XML Schema
- C) OpenAPI v3 Schema
- D) GraphQL Schema
Show Answer
Answer: C) OpenAPI v3 Schema
Explanation: The format used to define validation schemas for CRDs (CustomResourceDefinitions) in Kubernetes is OpenAPI v3 Schema. This schema defines the structure and field types of custom resources and is used by the API server to validate resource creation and update requests.
Example of CRD validation schema:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: ["spec"]
properties:
spec:
type: object
required: ["cronSpec", "image"]
properties:
cronSpec:
type: string
pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
image:
type: string
replicas:
type: integer
minimum: 1
maximum: 10
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ctIn this example, the openAPIV3Schema field defines the following validation rules:
- The
specfield is required. - Within
spec, thecronSpecandimagefields are required. cronSpecis a string and must follow the cron expression pattern.imageis a string.replicasis an integer and must be between 1 and 10.
OpenAPI v3 Schema provides various validation features:
- Specifying required fields
- Data type validation (string, number, boolean, object, array, etc.)
- String pattern validation (regular expressions)
- Number range validation (minimum, maximum)
- Array length validation
- Enum value validation
- Nested object structure definition
Issues with other options:
- JSON Schema is the basis for OpenAPI, but Kubernetes specifically uses OpenAPI v3 Schema.
- XML Schema is not used in the Kubernetes API.
- GraphQL Schema is used for GraphQL APIs but not for the Kubernetes API.
- What is the main benefit of enabling the status subresource for custom resources in Kubernetes?
- A) Faster resource creation
- B) Separation of spec and status updates and RBAC control
- C) Automatic backup and recovery features
- D) Simplified resource version management
Show Answer
Answer: B) Separation of spec and status updates and RBAC control
Explanation: The main benefit of enabling the status subresource for custom resources in Kubernetes is the separation of spec and status updates and the ability to control access through RBAC (Role-Based Access Control).
Benefits of enabling the status subresource:
Separation of Concerns:
- The
specfield defines the desired state specified by users. - The
statusfield reports the actual state observed by controllers. - This separation clarifies the responsibilities of users and controllers.
- The
RBAC Control:
- Status update permissions can be granted only to controllers while giving regular users read-only permissions.
- This prevents unauthorized modification of status information.
Conflict Prevention:
- Even if a user updates
specwhile a controller updatesstatus, no conflict occurs. - This is because the two fields are updated via separate API requests.
- Even if a user updates
Scale Subresource Support:
- Enabling the status subresource also allows enabling the scale subresource.
- This enables the use of standard Kubernetes scaling tools like HPA (Horizontal Pod Autoscaler).
Example of enabling status subresource in CRD:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
versions:
- name: v1
served: true
storage: true
subresources:
status: {} # Enable status subresource
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
# Spec field definitions...
status:
type: object
properties:
# Status field definitions...
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTabExample of status update from controller:
// Update status only
statusUpdate := &v1alpha1.MyResource{}
statusUpdate.Name = instance.Name
statusUpdate.Namespace = instance.Namespace
statusUpdate.Status.Phase = "Running"
statusUpdate.Status.Message = "Resource is running"
_, err = c.clientset.MyGroup().MyResources(namespace).UpdateStatus(statusUpdate)Issues with other options:
- The status subresource does not improve resource creation speed.
- It does not provide automatic backup and recovery features.
- Resource version management is handled through the CRD's
versionsfield and is not directly related to the status subresource.
- What is the main purpose of Webhook Conversion in Kubernetes?
- A) Route API requests to external services
- B) Handle conversion between different versions of custom resources
- C) Convert authentication tokens to different formats
- D) Convert log data to structured formats
Show Answer
Answer: B) Handle conversion between different versions of custom resources
Explanation: The main purpose of Webhook Conversion in Kubernetes is to handle conversion between different versions of custom resources. This feature supports multiple versions of CRDs and enables smooth migration between versions.
Key characteristics of webhook conversion:
Multi-Version Support:
- CRDs can support multiple API versions simultaneously (e.g., v1alpha1, v1beta1, v1).
- Each version can have different schemas and fields.
Automatic Conversion:
- The API server automatically handles conversion between the version requested by the client and the storage version.
- The conversion webhook provides custom conversion logic in this process.
Storage Version Independence:
- Even if the storage version changes, clients using previous versions can continue to work.
- The webhook handles bidirectional conversion between old and new versions.
Example of conversion webhook configuration in CRD:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
# v1 schema definition...
- name: v1beta1
served: true
storage: false
schema:
openAPIV3Schema:
# v1beta1 schema definition...
conversion:
strategy: Webhook
webhook:
clientConfig:
service:
namespace: webhook-system
name: crd-conversion-webhook
path: /convert
caBundle: <base64-encoded-ca-cert>
conversionReviewVersions: ["v1", "v1beta1"]
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTabExample of conversion webhook server implementation:
func (s *WebhookServer) ServeConvert(w http.ResponseWriter, r *http.Request) {
var body []byte
if r.Body != nil {
if data, err := ioutil.ReadAll(r.Body); err == nil {
body = data
}
}
// Decode ConversionReview request
convertReview := v1.ConversionReview{}
if err := json.Unmarshal(body, &convertReview); err != nil {
// Error handling
return
}
// Perform conversion logic
if convertReview.Request.DesiredAPIVersion == "stable.example.com/v1" {
// v1beta1 -> v1 conversion
for i, obj := range convertReview.Request.Objects {
v1beta1Obj := &v1beta1.CronTab{}
if err := json.Unmarshal(obj.Raw, v1beta1Obj); err != nil {
// Error handling
return
}
// Conversion logic
v1Obj := &v1.CronTab{
Spec: v1.CronTabSpec{
CronSpec: v1beta1Obj.Spec.Cron, // Field name change
Image: v1beta1Obj.Spec.Image,
Replicas: v1beta1Obj.Spec.Replicas,
},
}
// Encode converted object
raw, err := json.Marshal(v1Obj)
if err != nil {
// Error handling
return
}
convertReview.Response.ConvertedObjects = append(
convertReview.Response.ConvertedObjects,
runtime.RawExtension{Raw: raw},
)
}
} else {
// v1 -> v1beta1 conversion
// Similar logic...
}
// Set response
convertReview.Response.UID = convertReview.Request.UID
convertReview.Response.Result.Status = "Success"
// Send response
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(convertReview)
}Issues with other options:
- Routing API requests to external services is the role of API aggregation.
- Converting authentication tokens is the role of authentication plugins.
- Converting log data is the role of logging systems.
- Which of the following is NOT a framework that helps develop Kubernetes operators?
- A) Operator Framework
- B) Kubebuilder
- C) Metacontroller
- D) Kubespray
Show Answer
Answer: D) Kubespray
Explanation: Kubespray is not a framework that helps develop Kubernetes operators. Kubespray is a tool for deploying and managing Kubernetes clusters using Ansible playbooks. It focuses on cluster installation and configuration and is not related to operator development.
Actual frameworks for Kubernetes operator development are:
Operator Framework:
- Operator development toolkit developed by Red Hat
- Key components:
- Operator SDK: Operator scaffolding and development tools
- Operator Lifecycle Manager (OLM): Operator installation and upgrade management
- Operator Metering: Operator usage reporting
- Supports Go, Ansible, and Helm-based operator development
Kubebuilder:
- Framework developed by Kubernetes SIG (Special Interest Group)
- SDK for developing controllers in Go
- Provides code generation, CRD management, and testing tools
- Based on controller-runtime library
Metacontroller:
- Lightweight webhook-based operator framework
- Can implement controller logic in various languages
- Declarative controller definition
- Suitable for quickly developing simple controllers
Feature comparison of each framework:
| Framework | Primary Language | Complexity | Features |
|---|---|---|---|
| Operator Framework | Go, Ansible, Helm | Medium-High | Comprehensive toolkit, various development options |
| Kubebuilder | Go | Medium | Standardized patterns, code generation tools |
| Metacontroller | Language-independent | Low | Webhook-based, simple implementation |
Operator development example (using Kubebuilder):
# Initialize project
kubebuilder init --domain example.com --repo github.com/example/my-operator
# Create API
kubebuilder create api --group apps --version v1alpha1 --kind MyApp
# Implement controller (edit controller.go file)
# Create CRD and deploy controller
make install
make deployExplanations of other options:
- Operator Framework is Red Hat's comprehensive operator development toolkit.
- Kubebuilder is a Go-based controller development framework developed by Kubernetes SIG.
- Metacontroller is a lightweight webhook-based operator framework.
- What is the main difference between Custom Resource Definitions (CRD) and Aggregated APIs in Kubernetes?
- A) CRDs do not support versioning, but Aggregated APIs do
- B) CRDs do not support validation schemas, but Aggregated APIs do
- C) CRDs are simple to implement but have limited flexibility, while Aggregated APIs are complex to implement but provide more flexibility
- D) CRDs only support cluster-scoped resources, and Aggregated APIs only support namespace-scoped resources
Show Answer
Answer: C) CRDs are simple to implement but have limited flexibility, while Aggregated APIs are complex to implement but provide more flexibility
Explanation: The main difference between Custom Resource Definitions (CRD) and Aggregated APIs in Kubernetes is the balance between implementation complexity and flexibility. CRDs are simple to implement but have limited flexibility, while Aggregated APIs are complex to implement but provide more flexibility.
Characteristics of CRDs (CustomResourceDefinitions):
- Simple implementation: You can define new API resources with a single YAML file.
- Uses existing API server: No need to implement a separate API server.
- Limited flexibility:
- Storage is limited to etcd.
- Inherits the behavior of the default API server.
- Difficult to implement complex validation or conversion logic.
- Extension through webhooks: Some functionality can be extended through validating webhooks, conversion webhooks, etc.
Characteristics of Aggregated APIs:
- Complex implementation: Must develop and deploy a separate API server.
- High flexibility:
- Can use custom storage backends
- Can implement complex business logic
- Can implement custom authentication and authorization logic
- Can implement special state calculation and conversion logic
- Full API server functionality: Can leverage all features of a standard Kubernetes API server.
Selection Criteria:
| Criteria | Choose CRD | Choose Aggregated API |
|---|---|---|
| Implementation complexity | Low - Simple YAML definition | High - Requires separate API server development |
| Development time | Short - Can implement in minutes | Long - Requires complete API server development |
| Maintenance | Easy - Managed by existing API server | Difficult - Requires maintaining separate service |
| Storage options | etcd only | Custom storage backends possible |
| Business logic | Limited - Implement via controllers | Flexible - Can implement directly in API server |
| Performance | Generally good | Custom optimization possible |
| Use cases | Simple CRUD operations, standard patterns | Complex API behavior, special validation/conversion |
Example Scenarios:
Suitable cases for CRDs:
- Simple application configuration management
- Basic CRUD operations as main requirements
- Rapid prototyping and development
Suitable cases for Aggregated APIs:
- Integration with external databases
- Complex data transformation and validation
- Special authentication mechanisms needed
- High-performance or special-purpose APIs
Issues with other options:
- CRDs do support versioning (A is incorrect).
- CRDs do support validation schemas through OpenAPI v3 Schema (B is incorrect).
- Both CRDs and Aggregated APIs support cluster-scoped and namespace-scoped resources (D is incorrect).
Short Answer Questions
- Explain how to define custom resources using CustomResourceDefinition (CRD) and how to set validation rules for those resources.
Show Answer
Answer:
How to Define CustomResourceDefinition (CRD):
CRD is a mechanism that extends the Kubernetes API to define new resource types. When you create a CRD, a new RESTful API endpoint is created, and you can manage that resource using standard tools like kubectl.
1. Basic CRD Structure:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: <plural>.<group> # e.g., crontabs.stable.example.com
spec:
group: <api-group> # e.g., stable.example.com
names:
kind: <kind-name> # e.g., CronTab
plural: <plural-name> # e.g., crontabs
singular: <singular-name> # e.g., crontab
shortNames: # optional
- <short-name> # e.g., ct
scope: Namespaced # or Cluster
versions:
- name: <version> # e.g., v1
served: true # whether to serve via API server
storage: true # whether this is the storage version
schema:
openAPIV3Schema:
# schema definition2. Setting Validation Rules:
Validation rules for CRDs are set through the openAPIV3Schema field. This schema follows OpenAPI v3 format and defines the structure and field types of resources.
Basic Validation Rules Example:
schema:
openAPIV3Schema:
type: object
required: ["spec"]
properties:
spec:
type: object
required: ["cronSpec", "image"]
properties:
cronSpec:
type: string
pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
image:
type: string
replicas:
type: integer
minimum: 1
maximum: 10
default: 13. Advanced Validation Features:
OpenAPI v3 Schema provides various validation features:
Required fields: Add field names to the
requiredarrayyamlrequired: ["fieldName1", "fieldName2"]Data types: Specify data types using the
typefieldyamltype: string | number | integer | boolean | array | objectString constraints: Validate string length and patterns
yamlminLength: 3 maxLength: 64 pattern: '^[a-z0-9]([-a-z0-9]*[a-z0-9])?$'Number constraints: Validate number ranges
yamlminimum: 0 maximum: 100 multipleOf: 5Array constraints: Validate array length and items
yamlminItems: 1 maxItems: 10 uniqueItems: true items: type: stringEnum values: Specify allowed value list
yamlenum: ["value1", "value2", "value3"]Default values: Specify default values for fields
yamldefault: "default-value"Additional properties: Control whether additional properties are allowed
yamladditionalProperties: false
4. Complete CRD Example:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: ["spec"]
properties:
spec:
type: object
required: ["cronSpec", "image"]
properties:
cronSpec:
type: string
pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
image:
type: string
replicas:
type: integer
minimum: 1
maximum: 10
default: 1
status:
type: object
properties:
active:
type: boolean
lastScheduleTime:
type: string
format: date-time
subresources:
status: {} # Enable status subresource
additionalPrinterColumns:
- name: Schedule
type: string
description: The cron schedule
jsonPath: .spec.cronSpec
- name: Image
type: string
description: The image to use
jsonPath: .spec.image
- name: Age
type: date
jsonPath: .metadata.creationTimestamp
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ct5. Applying and Using CRD:
# Apply CRD
kubectl apply -f crontab-crd.yaml
# Create custom resource
cat <<EOF | kubectl apply -f -
apiVersion: stable.example.com/v1
kind: CronTab
metadata:
name: my-crontab
spec:
cronSpec: "* * * * */5"
image: my-cron-image
replicas: 3
EOF
# View custom resources
kubectl get crontabs
kubectl get ct # Using short name6. Testing Validation Rules:
Creating a resource with invalid values will result in validation errors:
cat <<EOF | kubectl apply -f -
apiVersion: stable.example.com/v1
kind: CronTab
metadata:
name: invalid-crontab
spec:
cronSpec: "invalid-cron-spec" # Pattern mismatch
image: my-cron-image
replicas: 20 # Exceeds maximum
EOFThis command will return errors like:
Error from server (Invalid): error when creating "STDIN": admission webhook "validate-crontab.example.com" denied the request:
- spec.cronSpec: Invalid value: "invalid-cron-spec": does not match pattern '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
- spec.replicas: Invalid value: 20: must be less than or equal to 107. Best Practices:
- Clear and detailed schema definitions
- Explicitly specify required fields
- Provide appropriate default values
- Limit string patterns and number ranges
- Enable status subresource
- Configure additional printer columns
- Establish versioning strategy
- Explain the core concepts of the Kubernetes Operator Pattern and the common methods for implementing operators.
Show Answer
Answer:
Core Concepts of the Kubernetes Operator Pattern:
The operator pattern is a Kubernetes extension mechanism that encodes application-specific operational knowledge into software to automatically manage complex applications. This pattern mimics how a human operator manages complex systems.
1. Core Concepts:
- Declarative Management: Users declare the desired state, and the operator adjusts the current state to the desired state.
- Encoding Domain Knowledge: Codifies operational knowledge and best practices for specific applications.
- Reconciliation Loop: Continuously observes actual state and adjusts to desired state.
- Custom Resources: Used to store application-specific configuration and state.
- Controllers: Watch changes to custom resources and perform necessary tasks.
2. Common Functions of Operators:
- Installation and Upgrades: Deploy application components and upgrade versions
- Automatic Recovery: Detect failures and perform recovery tasks
- Backup and Restore: Automate data backup and restore processes
- Scaling: Automatic expansion and contraction based on workload requirements
- Configuration Management: Handle application-specific configuration changes
- Operations Automation: Automate routine operational tasks (e.g., database compaction, index rebuilding)
Methods for Implementing Operators:
1. Using Operator SDK:
Operator SDK is part of Red Hat's Operator Framework and is a tool that simplifies operator development.
# Install Operator SDK
curl -LO https://github.com/operator-framework/operator-sdk/releases/download/v1.25.0/operator-sdk_linux_amd64
chmod +x operator-sdk_linux_amd64
sudo mv operator-sdk_linux_amd64 /usr/local/bin/operator-sdk
# Create Go-based operator project
operator-sdk init --domain example.com --repo github.com/example/my-operator
# Create API
operator-sdk create api --group apps --version v1alpha1 --kind MyApp --resource --controller
# Create CRD
make manifests
# Build and deploy operator
make docker-build docker-push
make deploy2. Using Kubebuilder:
Kubebuilder is a framework developed by Kubernetes SIG that provides tools for controller development.
# Install Kubebuilder
curl -L https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH) | tar -xz -C /tmp/
sudo mv /tmp/kubebuilder_*/bin/kubebuilder /usr/local/bin/
# Initialize project
kubebuilder init --domain example.com --repo github.com/example/my-operator
# Create API
kubebuilder create api --group apps --version v1alpha1 --kind MyApp
# Create CRD and deploy controller
make install
make deploy3. Controller Implementation:
The core of an operator is the reconciliation function. This function observes the current state of custom resources and performs necessary tasks.
// Reconcile function example
func (r *MyAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := r.Log.WithValues("myapp", req.NamespacedName)
// Get custom resource
var myApp appsv1alpha1.MyApp
if err := r.Get(ctx, req.NamespacedName, &myApp); err != nil {
if errors.IsNotFound(err) {
// Resource deleted - perform cleanup
return ctrl.Result{}, nil
}
// Error occurred
return ctrl.Result{}, err
}
// 1. Check if required resources exist
deployment := &appsv1.Deployment{}
err := r.Get(ctx, types.NamespacedName{Name: myApp.Name, Namespace: myApp.Namespace}, deployment)
if errors.IsNotFound(err) {
// Create deployment if it doesn't exist
deployment = r.deploymentForMyApp(&myApp)
log.Info("Creating a new Deployment", "Deployment.Namespace", deployment.Namespace, "Deployment.Name", deployment.Name)
if err := r.Create(ctx, deployment); err != nil {
log.Error(err, "Failed to create new Deployment")
return ctrl.Result{}, err
}
// Deployment creation successful
return ctrl.Result{Requeue: true}, nil
} else if err != nil {
log.Error(err, "Failed to get Deployment")
return ctrl.Result{}, err
}
// 2. Check if deployment is in desired state
size := myApp.Spec.Size
if *deployment.Spec.Replicas != size {
deployment.Spec.Replicas = &size
if err := r.Update(ctx, deployment); err != nil {
log.Error(err, "Failed to update Deployment")
return ctrl.Result{}, err
}
// Deployment update successful
return ctrl.Result{Requeue: true}, nil
}
// 3. Update status
if myApp.Status.AvailableReplicas != deployment.Status.AvailableReplicas {
myApp.Status.AvailableReplicas = deployment.Status.AvailableReplicas
if err := r.Status().Update(ctx, &myApp); err != nil {
log.Error(err, "Failed to update MyApp status")
return ctrl.Result{}, err
}
}
return ctrl.Result{}, nil
}
// Deployment creation function
func (r *MyAppReconciler) deploymentForMyApp(m *appsv1alpha1.MyApp) *appsv1.Deployment {
ls := labelsForMyApp(m.Name)
replicas := m.Spec.Size
dep := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name,
Namespace: m.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: ls,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: ls,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{{
Image: m.Spec.Image,
Name: "myapp",
Ports: []corev1.ContainerPort{{
ContainerPort: 8080,
Name: "http",
}},
}},
},
},
},
}
// Set owner reference
ctrl.SetControllerReference(m, dep, r.Scheme)
return dep
}4. Custom Resource Definition:
Define the API for custom resources managed by the operator.
// MyApp API
type MyAppSpec struct {
// Application image
Image string `json:"image"`
// Number of replicas
Size int32 `json:"size"`
// Configuration options
Config map[string]string `json:"config,omitempty"`
}
type MyAppStatus struct {
// Number of available replicas
AvailableReplicas int32 `json:"availableReplicas"`
// Last update time
LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
// Status message
Message string `json:"message,omitempty"`
}
// MyApp resource
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Replicas",type=integer,JSONPath=`.spec.size`
// +kubebuilder:printcolumn:name="Available",type=integer,JSONPath=`.status.availableReplicas`
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
type MyApp struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec MyAppSpec `json:"spec,omitempty"`
Status MyAppStatus `json:"status,omitempty"`
}5. Ansible or Helm-Based Operators:
Operator SDK also supports operator development using Ansible or Helm in addition to Go.
Ansible-based operator:
# Create Ansible-based operator
operator-sdk init --plugins=ansible --domain example.com
operator-sdk create api --group apps --version v1alpha1 --kind MyApp --generate-role
# Edit roles/myapp/tasks/main.ymlHelm-based operator:
# Create Helm-based operator
operator-sdk init --plugins=helm --domain example.com --helm-chart=<chart-name>6. Deploying and Testing Operators:
# Deploy operator
make deploy
# Create custom resource
kubectl apply -f config/samples/
# Check operator logs
kubectl logs -f deployment/my-operator-controller-manager -n my-operator-system
# Check resource status
kubectl get myapps
kubectl describe myapp my-app7. Operator Maturity Levels:
The operator maturity model defines the capability levels of operators:
- Basic Install: Application installation and configuration
- Seamless Upgrades: Automatic upgrades between versions
- Full Lifecycle: Backup, restore, failure recovery, etc.
- Deep Insights: Auto-scaling, tuning, etc.
- Auto Pilot: Monitoring-based automatic optimization
8. Best Practices:
- Implement features incrementally (start with simple things)
- Thorough error handling and logging
- Ensure idempotency (same result for same input)
- Set owner references (resource hierarchy and garbage collection)
- Report progress through status updates
- Write unit tests and integration tests
- Clear documentation
- Explain the types of Admission Webhooks in Kubernetes and the use cases for each.
Show Answer
Answer:
Types and Use Cases of Kubernetes Admission Webhooks:
Admission webhooks are mechanisms that can intercept and modify or validate requests before the Kubernetes API server stores them in persistent storage (etcd). Admission webhooks are broadly divided into two types: Mutating webhooks and Validating webhooks.
1. Mutating Webhook:
Mutating webhooks can modify request objects coming into the API server. These webhooks run before validating webhooks.
Key Characteristics:
- Can modify request objects
- Multiple mutating webhooks run in a chain
- Each webhook receives the object modified by the previous webhook
Configuration Example:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: sidecar-injector
webhooks:
- name: sidecar-injector.example.com
clientConfig:
service:
namespace: webhook-system
name: sidecar-injector
path: "/inject"
caBundle: <base64-encoded-ca-cert>
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
scope: "Namespaced"
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
timeoutSeconds: 5Common Use Cases:
Sidecar Container Injection:
- Automatic proxy sidecar injection in service meshes like Istio and Linkerd
- Adding logging and monitoring sidecars
- Example: Istio's sidecar injector automatically adds Envoy proxy containers when pods are created
Setting Defaults:
- Automatic resource requests and limits setting
- Applying security context defaults
- Automatic addition of labels and annotations
- Example: Setting default CPU and memory requests for all pods
Applying Image Policies:
- Modifying image registry URLs
- Converting image tags to digests
- Example: Changing
nginx:latesttointernal-registry.example.com/nginx:v1.19.0
Volume Modifications:
- Adding default volume mounts
- Automatic ConfigMap or Secret mounting
- Example: Automatic service account token volume mounting for all pods
Applying Network Policies:
- Adding default network settings
- Modifying DNS configuration
- Example: Applying specific DNS settings to all pods in a specific namespace
2. Validating Webhook:
Validating webhooks can validate requests coming into the API server and allow or deny them. These webhooks run after mutating webhooks.
Key Characteristics:
- Cannot modify request objects
- Can only allow or deny requests
- Multiple validating webhooks run in parallel
- All webhooks must allow the request for it to be processed
Configuration Example:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: pod-policy-validator
webhooks:
- name: pod-policy.example.com
clientConfig:
service:
namespace: webhook-system
name: pod-policy-validator
path: "/validate"
caBundle: <base64-encoded-ca-cert>
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
scope: "Namespaced"
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
timeoutSeconds: 5Common Use Cases:
Enforcing Security Policies:
- Prohibiting privileged containers
- Prohibiting root user execution
- Restricting host network/PID/IPC usage
- Example: Denying pods running in privileged mode
Validating Resource Constraints:
- Making resource requests and limits mandatory
- Applying resource caps
- Enforcing QoS classes
- Example: Denying pods without memory limits
Validating Image Policies:
- Allowing only approved registries
- Prohibiting latest tag usage
- Verifying vulnerability scan results
- Example: Allowing only images from official registries
Validating Labels and Annotations:
- Checking required labels
- Validating label formats
- Example: Making
appandenvironmentlabels mandatory for all pods
Namespace-Based Policies:
- Per-namespace resource limits
- Per-namespace feature restrictions
- Example: Applying stricter policies in production namespaces
3. Webhook Implementation Methods:
Admission webhooks are implemented as services that provide HTTPS endpoints. These services receive AdmissionReview requests, process them, and return AdmissionResponse.
Basic Webhook Server Implementation Example (Go):
package main
import (
"encoding/json"
"io/ioutil"
"net/http"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
)
var (
runtimeScheme = runtime.NewScheme()
codecs = serializer.NewCodecFactory(runtimeScheme)
deserializer = codecs.UniversalDeserializer()
)
// Mutating webhook handler
func mutateHandler(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusBadRequest)
return
}
// Decode AdmissionReview request
admissionReview := admissionv1.AdmissionReview{}
if _, _, err := deserializer.Decode(body, nil, &admissionReview); err != nil {
http.Error(w, "Failed to decode request", http.StatusBadRequest)
return
}
// Decode pod object
pod := corev1.Pod{}
if err := json.Unmarshal(admissionReview.Request.Object.Raw, &pod); err != nil {
http.Error(w, "Failed to decode pod", http.StatusBadRequest)
return
}
// Create patch (add sidecar container)
patch := []map[string]interface{}{
{
"op": "add",
"path": "/spec/containers/-",
"value": map[string]interface{}{
"name": "sidecar",
"image": "sidecar-image:latest",
"resources": map[string]interface{}{
"limits": map[string]interface{}{
"cpu": "100m",
"memory": "100Mi",
},
"requests": map[string]interface{}{
"cpu": "50m",
"memory": "50Mi",
},
},
},
},
}
// Convert patch to JSON
patchBytes, err := json.Marshal(patch)
if err != nil {
http.Error(w, "Failed to marshal patch", http.StatusInternalServerError)
return
}
// Create response
admissionResponse := admissionv1.AdmissionResponse{
UID: admissionReview.Request.UID,
Allowed: true,
Patch: patchBytes,
PatchType: func() *admissionv1.PatchType {
pt := admissionv1.PatchTypeJSONPatch
return &pt
}(),
}
// Send response
admissionReview.Response = &admissionResponse
resp, err := json.Marshal(admissionReview)
if err != nil {
http.Error(w, "Failed to marshal response", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
}
// Validating webhook handler
func validateHandler(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusBadRequest)
return
}
// Decode AdmissionReview request
admissionReview := admissionv1.AdmissionReview{}
if _, _, err := deserializer.Decode(body, nil, &admissionReview); err != nil {
http.Error(w, "Failed to decode request", http.StatusBadRequest)
return
}
// Decode pod object
pod := corev1.Pod{}
if err := json.Unmarshal(admissionReview.Request.Object.Raw, &pod); err != nil {
http.Error(w, "Failed to decode pod", http.StatusBadRequest)
return
}
// Validation logic
allowed := true
var message string
// Check for privileged containers
for _, container := range pod.Spec.Containers {
if container.SecurityContext != nil && container.SecurityContext.Privileged != nil && *container.SecurityContext.Privileged {
allowed = false
message = "Privileged containers are not allowed"
break
}
}
// Create response
admissionResponse := admissionv1.AdmissionResponse{
UID: admissionReview.Request.UID,
Allowed: allowed,
}
if !allowed {
admissionResponse.Result = &metav1.Status{
Message: message,
Status: "Failure",
Reason: metav1.StatusReasonForbidden,
Code: 403,
}
}
// Send response
admissionReview.Response = &admissionResponse
resp, err := json.Marshal(admissionReview)
if err != nil {
http.Error(w, "Failed to marshal response", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
}
func main() {
http.HandleFunc("/mutate", mutateHandler)
http.HandleFunc("/validate", validateHandler)
fmt.Println("Starting webhook server on :8443")
http.ListenAndServeTLS(":8443", "tls.crt", "tls.key", nil)
}4. Webhook Deployment and Configuration:
Webhook servers are typically deployed within the Kubernetes cluster and require a service and TLS certificates.
# Webhook server deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: webhook-server
namespace: webhook-system
spec:
replicas: 1
selector:
matchLabels:
app: webhook-server
template:
metadata:
labels:
app: webhook-server
spec:
containers:
- name: server
image: webhook-server:latest
ports:
- containerPort: 8443
volumeMounts:
- name: tls
mountPath: "/etc/webhook/certs"
readOnly: true
volumes:
- name: tls
secret:
secretName: webhook-server-tls
---
# Webhook server service
apiVersion: v1
kind: Service
metadata:
name: webhook-server
namespace: webhook-system
spec:
selector:
app: webhook-server
ports:
- port: 443
targetPort: 84435. Best Practices:
- Performance Optimization: Webhooks are in the API server request path, so they must respond quickly.
- Error Handling: Consider behavior when webhook server fails and set
failurePolicyappropriately. - Scope Limitation: Apply webhooks only to necessary resources and operations.
- Testing: Thoroughly test webhook behavior in various scenarios.
- Monitoring: Monitor webhook server performance and errors.
- Version Management: Support multiple versions of AdmissionReview in preparation for API version changes.
Hands-on Questions
- Write a CustomResourceDefinition (CRD) that meets the following requirements:
- API Group: webapp.example.com
- Version: v1
- Kind: WebApp
- Scope: Namespaced
- Required fields: spec.image, spec.replicas
- Validation rules: replicas must be an integer between 1 and 10
- Enable status subresource
Show Answer
Answer:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: webapps.webapp.example.com
spec:
group: webapp.example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
required: ["spec"]
properties:
spec:
type: object
required: ["image", "replicas"]
properties:
image:
type: string
replicas:
type: integer
minimum: 1
maximum: 10
port:
type: integer
default: 80
env:
type: array
items:
type: object
required: ["name"]
properties:
name:
type: string
value:
type: string
status:
type: object
properties:
availableReplicas:
type: integer
phase:
type: string
subresources:
status: {}
additionalPrinterColumns:
- name: Replicas
type: integer
jsonPath: .spec.replicas
- name: Image
type: string
jsonPath: .spec.image
- name: Age
type: date
jsonPath: .metadata.creationTimestamp
scope: Namespaced
names:
plural: webapps
singular: webapp
kind: WebApp
shortNames:
- waThis CRD has the following characteristics:
Basic Information:
- API Group:
webapp.example.com - Version:
v1 - Kind:
WebApp - Scope:
Namespaced
- API Group:
Schema Validation:
- The
specfield is required. spec.imageandspec.replicasare required fields.spec.replicasmust be an integer between 1 and 10.spec.portis an optional field with a default value of 80.spec.envis an optional field defining an array of environment variables.
- The
Status Subresource:
- The
statussubresource is enabled so controllers can update status. status.availableReplicasandstatus.phasefields are defined.
- The
Additional Printer Columns:
- When running
kubectl get webapps, Replicas, Image, and Age columns are displayed.
- When running
Name Configuration:
- Plural:
webapps - Singular:
webapp - Kind:
WebApp - Short name:
wa
- Plural:
You can create custom resources like this using this CRD:
apiVersion: webapp.example.com/v1
kind: WebApp
metadata:
name: my-webapp
namespace: default
spec:
image: nginx:1.19
replicas: 3
port: 8080
env:
- name: ENV_VAR1
value: "value1"
- name: ENV_VAR2
value: "value2"Controllers can watch this resource and update status:
status:
availableReplicas: 3
phase: Running- Write a Mutating Admission Webhook configuration that meets the following requirements:
- Add sidecar container to all pod creation requests
- Apply only to a specific namespace (monitoring)
- Webhook service: webhook-service.webhook-system.svc
- Path: /mutate
Show Answer
Answer:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: sidecar-injector
webhooks:
- name: sidecar-injector.example.com
clientConfig:
service:
namespace: webhook-system
name: webhook-service
path: "/mutate"
caBundle: ${CA_BUNDLE} # Replace with base64-encoded CA certificate in actual environment
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
scope: "Namespaced"
namespaceSelector:
matchLabels:
monitoring-injection: enabled
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
timeoutSeconds: 5
failurePolicy: Fail
---
# Add label to namespace
apiVersion: v1
kind: Namespace
metadata:
name: monitoring
labels:
monitoring-injection: enabledThis configuration has the following characteristics:
Webhook Configuration:
- Name:
sidecar-injector - Webhook service:
webhook-service.webhook-system.svc - Path:
/mutate
- Name:
Scope:
- API Group:
""(core API group) - API Version:
v1 - Operation:
CREATE(apply only on pod creation) - Resource:
pods - Scope:
Namespaced
- API Group:
Namespace Selector:
- Apply only to namespaces with
monitoring-injection: enabledlabel - Add this label to the
monitoringnamespace
- Apply only to namespaces with
Additional Settings:
admissionReviewVersions: Supported AdmissionReview API versionssideEffects: No side effects from webhooktimeoutSeconds: Webhook response wait timefailurePolicy: Deny requests on webhook failure
The webhook server should implement logic like this:
func mutateHandler(w http.ResponseWriter, r *http.Request) {
// Decode request
body, _ := ioutil.ReadAll(r.Body)
admissionReview := admissionv1.AdmissionReview{}
deserializer.Decode(body, nil, &admissionReview)
// Decode pod object
pod := corev1.Pod{}
json.Unmarshal(admissionReview.Request.Object.Raw, &pod)
// Define sidecar container
sidecarContainer := corev1.Container{
Name: "monitoring-sidecar",
Image: "monitoring-agent:latest",
Resources: corev1.ResourceRequirements{
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("100m"),
corev1.ResourceMemory: resource.MustParse("100Mi"),
},
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("50m"),
corev1.ResourceMemory: resource.MustParse("50Mi"),
},
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "shared-data",
MountPath: "/var/monitoring",
},
},
}
// Create patch
patch := []map[string]interface{}{
{
"op": "add",
"path": "/spec/containers/-",
"value": sidecarContainer,
},
{
"op": "add",
"path": "/spec/volumes/-",
"value": map[string]interface{}{
"name": "shared-data",
"emptyDir": map[string]interface{}{},
},
},
}
// Convert patch to JSON
patchBytes, _ := json.Marshal(patch)
// Create response
admissionResponse := admissionv1.AdmissionResponse{
UID: admissionReview.Request.UID,
Allowed: true,
Patch: patchBytes,
PatchType: func() *admissionv1.PatchType {
pt := admissionv1.PatchTypeJSONPatch
return &pt
}(),
}
// Send response
admissionReview.Response = &admissionResponse
resp, _ := json.Marshal(admissionReview)
w.Header().Set("Content-Type", "application/json")
w.Write(resp)
}This webhook automatically adds a monitoring sidecar container to all pods created in the monitoring namespace. The sidecar container uses a monitoring agent image and mounts a shared volume to share data with the main container.