Kubernetes (part-7)

praduman_cnd

Praduman

Posted on September 23, 2024

Kubernetes (part-7)

Understanding ConfigMap: Simplify Your Kubernetes Configuration Management

It is used to store non-confidential configuration data in key-value pairs. It keep configuration separate from the application code, that makes it easier to manage and update without redeploying the entire application

Example 1: Passing Database User to MySQL Pod Using ConfigMap

  • Create the ConfigMap (cm1.yaml): The ConfigMap will contain the database user and password

    # cm1.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: bootcamp-configmap
    data:
      username: "saiyam"
      database_name: "exampledb"
    
```basic
kubectl apply -f cm1.yaml
```
Enter fullscreen mode Exit fullscreen mode
  • Create the Pod (pod1.yaml): The Pod will run a MySQL container and use the environment variables from the ConfigMap

    # pod1.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: mysql-pod
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
          - name: MYSQL_USER
            valueFrom:
              configMapKeyRef:
                name: bootcamp-configmap
                key: username
          - name: MYSQL_DATABASE
            valueFrom:
              configMapKeyRef:
                name: bootcamp-configmap
                key: database_name
          - name: MYSQL_PASSWORD
            value: demo123  # Specify a strong password.
          - name: MYSQL_ROOT_PASSWORD
            value: demo345 # You should change this value.
        ports:
          - containerPort: 3306
            name: mysql
        volumeMounts:
          - name: mysql-storage
            mountPath: /var/lib/mysql
      volumes:
        - name: mysql-storage
          emptyDir: {}
    
```basic
 kubectl apply -f pod1.yaml
```
Enter fullscreen mode Exit fullscreen mode
  • Access the MySQL Pod: Once the Pod is running, connect to the MySQL container and verify the user setup

    kubectl exec -it mysql-pod -- mysql -u root -p
    

    If asks for password , Use that defined in the ConfigMap

  • Run MySQL Commands: Inside the MySQL prompt, run the following commands to verify the users and databases:

    SELECT user FROM mysql.user;
    SHOW DATABASES;
    

Example 2: Managing Dev/Prod Properties with ConfigMap

  • Create the ConfigMap (cm2.yaml)

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: app-config-dev
    data:
      settings.properties: |
        # Development Configuration
        debug=true
        database_url=http://dev-db.example.com
        featureX_enabled=false
    
    ---
    
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: app-config-prod
    data:
      settings.properties: |
        # Production Configuration
        debug=false
        database_url=http://prod-db.example.com
        featureX_enabled=true
    
```basic
kubectl apply -f cm2.yaml
```
Enter fullscreen mode Exit fullscreen mode
  • Create the Pod (pod2.yaml)

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-web-app
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: my-web-app
      template:
        metadata:
          labels:
            app: my-web-app
        spec:
          containers:
          - name: web-app-container
            image: nginx  
            ports:
            - containerPort: 80
            env:
            - name: ENVIRONMENT
              value: "development"  
            volumeMounts:
            - name: config-volume
              mountPath: /etc/config
          volumes:
          - name: config-volume
            configMap:
              name: app-config-dev
    
```yaml
kubectl apply -f pod2.yaml
```
Enter fullscreen mode Exit fullscreen mode
  • Verify the ConfigMap is Mounted: After the Pod is running, you can check if the settings.properties file has been correctly mounted and read its contents

    kubectl exec -it app-pod -- cat /etc/config/settings.properties
    

    This should display the content of the settings.properties file:

    # Development Configuration
    debug=true
    database_url=http://dev-db.example.com
    featureX_enabled=false
    
  • Switch to Production: To use the production configuration instead, update the Deployment to mount app-config-prod.

    Change this part in pod2.yaml:

    configMap:
      name: app-config-prod
    

    Reapply the deployment

    kubectl apply -f pod2.yaml
    

    Now, if you check the configuration inside the pod, you’ll see the production settings:

    # Production Configuration
    debug=false
    database_url=http://prod-db.example.com
    featureX_enabled=true
    

Example 3: Accessing ConfigMap Programmatically with Python

  • read_config.py: This Python script reads and prints the contents of the app-config ConfigMap in the default namespace

    from kubernetes import client, config
    
    def main():
        # Load the Kubernetes configuration
        config.load_incluster_config()
    
        v1 = client.CoreV1Api()
        config_map_name = 'app-config'
        namespace = 'default'
    
        try:
            # Read the ConfigMap
            config_map = v1.read_namespaced_config_map(config_map_name, namespace)
            print("ConfigMap data:")
            for key, value in config_map.data.items():
                print(f"{key}: {value}")
        except client.exceptions.ApiException as e:
            print(f"Exception when calling CoreV1Api->read_namespaced_config_map: {e}")
    
    if __name__ == '__main__':
        main()
    
  • Dockerfile: This Dockerfile builds the image that runs the Python script.

    # Use a lightweight Python image
    FROM python:3.8-slim
    
    # Install the Kubernetes Python client
    RUN pip install kubernetes
    
    # Copy the Python script
    COPY read_config.py /read_config.py
    
    # Set the command to run the script
    CMD ["python", "/read_config.py"]
    
  • Build the Docker Image: Build the Docker image using the provided Dockerfile and push it to a public image registry (in this case, ttl.sh)

    docker build -t ttl.sh/hindi-boot:1h .
    docker push ttl.sh/hindi-boot:1h
    
  • app.yaml: This YAML file defines all the Kubernetes resources: the ConfigMap, Deployment, Role, and RoleBinding.

    # ConfigMap storing some example properties
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: app-config
      namespace: default
    data:
      example.property: "Hello, world!"
      another.property: "Just another example."
    ---
    # Deployment to run the Python script in a pod
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: config-reader-deployment
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: config-reader
      template:
        metadata:
          labels:
            app: config-reader
        spec:
          containers:
          - name: config-reader
            image: ttl.sh/hindi-boot:1h
            imagePullPolicy: Always
    ---
    # Role granting read access to ConfigMaps in the default namespace
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: default
      name: config-reader
    rules:
    - apiGroups: [""]
      resources: ["configmaps"]
      verbs: ["get", "list", "watch"]
    ---
    # RoleBinding to attach the Role to the default ServiceAccount
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: read-configmaps
      namespace: default
    subjects:
    - kind: ServiceAccount
      name: default 
      namespace: default
    roleRef:
      kind: Role
      name: config-reader
      apiGroup: rbac.authorization.k8s.io
    
  • Apply the Kubernetes Resources: Deploy the ConfigMap, Deployment, and RBAC resources to Kubernetes.

    kubectl apply -f app.yaml
    
  • Check the Logs: After the pod is running, you can check the logs to see if the ConfigMap has been read successfully.

    kubectl logs -l app=config-reader
    

    The output should display the content of the ConfigMap

    ConfigMap data:
    example.property: Hello, world!
    another.property: Just another example.
    

Secrets in Kubernetes: Securely Manage Sensitive Information

When deploying applications in Kubernetes, you often need to handle sensitive information such as passwords, API keys, or tokens. Storing these directly in your code or configuration files can be insecure. Kubernetes Secrets provide a way to securely store and manage sensitive information.

Unlike ConfigMaps (which store non-sensitive configuration data), Secrets are designed for security. They store data in an encoded format (Base64) and can be mounted into Pods or accessed as environment variables.

Types of Kubernetes Secrets: Opaque, TLS, and Docker Registry

  • Opaque Secret: General-purpose secret, commonly used for storing credentials.

  • TLS Secret: Specifically for storing SSL/TLS certificates.

  • Docker Registry Secret: For storing Docker registry credentials, used for pulling private images.

Example 1: Creating a Kubernetes Secret Using YAML

  • Encode your values in Base64


bash
echo -n 'my-db-username' | base64
echo -n 'my-db-password' | base64

This will return


bash
bXktZGItdXNlcm5hbWU=
bXktZGItcGFzc3dvcmQ=

  • Create the Secret YAML file (secret.yaml)


yaml
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: opaque
data:
username: bXktZGItdXNlcm5hbWU=
password: bXktZGItcGFzc3dvcmQ=

Apply the secret


bash
kubectl apply -f secret.yaml

  • To view the secret


bash
kubectl get secret

  • To decrypt the encrypted data


bash
echo "put-encrypted-data" | base64 -d

Example 2: Creating a Kubernetes Secret from the Command Line

kubectl create secret generic db-secret \
  --from-literal=username=my-db-username \
  --from-literal=password=my-db-password
Enter fullscreen mode Exit fullscreen mode

Using Secrets in a Pod: Environment Variables and Volume Mounts

Once the Secret is created, you can use it in a Pod as either environment variables or mounted as files

  • Example: Using a Secret as Environment Variables

    apiVersion: v1
    kind: Pod
    metadata:
      name: db-app
    spec:
      containers:
      - name: app-container
        image: my-app:latest
        env:
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password
    

    Here, the username and password from the Secret are injected into the container as environment variables

  • Example: Mounting a Secret as a Volume

    apiVersion: v1
    kind: Pod
    metadata:
      name: app-with-secret
    spec:
      containers:
      - name: app-container
        image: my-app:latest
        volumeMounts:
        - name: secret-volume
          mountPath: /etc/secrets
          readOnly: true
      volumes:
      - name: secret-volume
        secret:
          secretName: db-secret
    

    This will mount the Secret’s data into /etc/secrets/ inside the container

Storing SSH Private Keys in Kubernetes Secrets

kubectl create secret generic my-ssh-key-secret \
--from-file=ssh-privatekey=/path/to/.ssh/id_rsa \
--type=kubernetes.io/ssh-auth
Enter fullscreen mode Exit fullscreen mode

--from-file=ssh-privatekey=/path/to/.ssh/id_rsa:

  • --from-file: Specifies that the content for the Secret should come from a file.

  • ssh-privatekey: The key under which the private key will be stored in the Secret.

  • /path/to/.ssh/id_rsa: Path to the actual SSH private key file (usually located in ~/.ssh/id_rsa).

--type=kubernetes.io/ssh-auth:

  • This specifies that the Secret is of type kubernetes.io/ssh-auth, which is used for SSH authentication.

Managing SSL/TLS Certificates with Kubernetes TLS Secrets

kubectl create secret tls my-tls-secret \
--cert=path/to/cert/file \
--key=path/to/key/file
Enter fullscreen mode Exit fullscreen mode

--cert=path/to/cert/file:

  • This specifies the path to the TLS certificate file. Replace path/to/cert/file with the actual path to your .crt (certificate) file.

--key=path/to/key/file:

  • This specifies the path to the TLS private key file. Replace path/to/key/file with the actual path to your private key file (typically .key).

MySQL Example: Combining ConfigMap and Secrets in Kubernetes

  • create a configmap (myconfig.yaml)

    apiVersion: v1
    kind: configMap
    metadata:
       name: bootcamp-configMap
    data: 
       username: "praduman"
       database_name: "my-db"
    
```bash
kubectl apply -f myconfig.yaml
```
Enter fullscreen mode Exit fullscreen mode
  • create secrets (mysecret.yaml)

    echo -n 'rootPass' | base64
    echo -n 'userPass' | base64
    
```yaml
apiVersion: v1
kind: Secret
metadata: 
   name: mysql-root-pass
type: Opaque
data: 
   password: <use-base64-encoded>
---
apiVersion: v1
kind: Secret
metadata: 
   name: mysql-user-pass
type: Opaque
data: 
   password: <use-base64-encoded>
```
Enter fullscreen mode Exit fullscreen mode
```bash
kubectl apply -f mysecret.yaml
```
Enter fullscreen mode Exit fullscreen mode
  • YAML file of deployment using both configMap and Secret(deploy.yaml)

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mysql
    spec:
      selector:
        matchLabels:
          app: mysql
      template:
        metadata:
          labels:
            app: mysql
        spec:
          containers:
          - name: mysql
            image: mysql:5.7
            env:
              - name: MYSQL_ROOT_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: mysql-root-pass
                    key: password
              - name: MYSQL_USER
                valueFrom:
                  configMapKeyRef:
                    name: bootcamp-configmap
                    key: username
              - name: MYSQL_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: mysql-user-pass
                    key: password
              - name: MYSQL_DATABASE
                valueFrom:
                  configMapKeyRef:
                    name: bootcamp-configmap
                    key: database_name
            ports:
              - containerPort: 3306
            volumeMounts:
              - name: mysql-storage
                mountPath: /var/lib/mysql
          volumes:
            - name: mysql-storage
              emptyDir: {}
    
```bash
kubectl apply -f deploy.yaml
```
Enter fullscreen mode Exit fullscreen mode
  • Access the MYSQL pod

    kubectl exec -it <pod-name> -- mysql -u root -p
    

Conclusion

In this article, we explored the essential concepts of Kubernetes ConfigMaps and Secrets, highlighting their importance in managing configuration data and sensitive information securely. ConfigMaps allow you to decouple configuration from application code, making updates seamless without redeploying the entire application. Secrets, on the other hand, provide a secure way to handle sensitive data like passwords and API keys, ensuring they are not exposed in your codebase.

We provided practical examples demonstrating how to use ConfigMaps and Secrets in various scenarios, such as passing database credentials to a MySQL Pod, managing environment-specific properties, and accessing configuration programmatically with Python. Additionally, we covered the different types of Secrets, including Opaque, TLS, and Docker Registry Secrets, and how to use them in Pods as environment variables or volume mounts.

By understanding and implementing these Kubernetes features, you can enhance the security and manageability of your applications, ensuring a more robust and flexible deployment process.

💖 💪 🙅 🚩
praduman_cnd
Praduman

Posted on September 23, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related