A How To Guide: Remotely Accessing Minikube Kubernetes on KVM
Run and remotely access a Minikube Kubernetes cluster using the KVM on your computer
Read MorePublished on Sep 17, 2024 by Sep Dehpour
TLDR; I had a brilliant idea to write logs to a file on Minikube and have those logs persist between the restarts. I had to jump through some hoops. The main one was realizing that I had to change the folder ownership of where the files will persist within Minikube itself and use hostPath
volume type on the pod so that I could persist the logs in Minikube.
Normally, on a managed Kubernetes cluster, you write the logs to stdout/stderr. The logs automatically end up in a logs bucket in the case of Google Cloud, and you can view them on Cloud logging. You don’t “lose” the logs. But with Minikube, you will.
/data/*
/data/logs-data
/data/logs-data
that is owned by root./data/logs-data
In the Dockerfile, we want to explicitly assign a user_id to the user we want to run inside Docker. In this case, we create a nonroot user:
FROM ...
RUN adduser --disabled-password --gecos "" --uid 1000 --shell /bin/bash nonroot
RUN mkdir -p /var/logs-data && \
chown nonroot:nonroot /var/logs-data && \
chmod 755 /var/logs-data
USER nonroot
...
CMD ["sleep", "infinity"]
The key here is assigning an explicit ID to the nonroot user by passing –uid 1000. The nonroot user won’t need a password to log in, hence the --disable-password
flag. We won’t be passing name and other information when creating the user so we do --gecos ""
. While we are at it let’s assign a default shell to the user too: --shell /bin/bash
minikube ssh "sudo mkdir -p /data/logs;sudo chown 1000:1000 /data/logs-data"
We create the /data/logs folder inside minikube proactively and assign the user_id 1000 as the owner. Note that we are using the same ID that we explicitly added in the Dockerfile.
We will use a hostPath
volume type. A hostPath volume mounts a file or directory from the host node’s filesystem into your Pod. In this case directly from Minikube.
We will explicitly tell Kubernetes to use user_id 1000 for all operations in the docker image by passing fsGroup
, runAsGroup
, and runAsUser
.
Example:
apiVersion: v1
kind: PersistentVolume
metadata:
name: logs-data
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 1Gi
hostPath:
path: /data/logs-data # Host path for Minikube node
storageClassName: standard
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: logs-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
volumeName: logs-data
---
apiVersion: batch/v1
kind: Job
metadata:
name: myapp
labels:
app: myapp
spec:
template:
spec:
securityContext:
fsGroup: 1000 # Group ID from atlas docker image nonroot user
runAsGroup: 1000 # Group ID from atlas docker image nonroot user
runAsUser: 1000 # User ID from atlas docker image nonroot user
containers:
- name: main
image: path_to_image
command:
- sleep
- infinity
volumeMounts:
- name: logs-data
mountPath: /var/logs-data
restartPolicy: Never
volumes:
- name: logs-data
persistentVolumeClaim:
claimName: logs-data
When we apply the above yaml file, we can start writing logs to files inside /var/logs-data
which will end up inside /data/logs-data on Minikube. These will persist when the pods restart, killed, and even when Minikube restarts!
If you want to know what fsGroup
, runAsGroup
, and runAsUser
are, here is some more material to read:
In Kubernetes, fsGroup
, runAsGroup
, and runAsUser
are part of the securityContext
for pods and containers. These fields are used to control the ownership and permissions for processes and files within the containers, helping you run containers with non-root users and ensuring proper access control. Here’s an explanation of each:
runAsUser
: Definition: Specifies the user ID (UID
) that the container’s process should run as.
Purpose: Ensures that processes inside the container run as a non-root user, improving security by avoiding the use of the default root user in the container.
Effect: All processes in the container will run as this specified user. If a container image defines a specific user, runAsUser
will override it.
Example:
securityContext:
runAsUser: 1000 # Process will run as user with UID 1000
Use Case: If your container image is based on a Linux system, you can create users inside the image with specific UIDs, such as 1000
for a non-root user, and then use runAsUser
to run the container process under this user. This is useful for avoiding privilege escalation or preventing containerized processes from running as root.
runAsGroup
: Definition: Specifies the group ID (GID
) that the container’s process should run as.
Purpose: Similar to runAsUser
, but it controls the primary group under which the process will run.
Effect: All processes in the container will run under this group. If the image specifies a group, runAsGroup
will override it.
Example:
securityContext:
runAsGroup: 1000 # Process will run with GID 1000
Use Case: You can ensure that the process in the container has the appropriate group access to certain files or directories. For instance, if your container process needs access to files owned by a particular group (like group 1000
), runAsGroup
ensures the process has the correct group permissions.
fsGroup
: Definition: Specifies the group ID (GID
) for file system access control.
Purpose: Allows you to set a group that will own the files created by the container and control access to shared volumes. This ensures proper group-based access to shared resources like volumes.
Effect:
fsGroup
specified.PersistentVolume
or EmptyDir
), not to hostPath
volumes.Example:
securityContext:
fsGroup: 2000 # Files on mounted volumes will have GID 2000
Use Case: When using shared storage (like PersistentVolume
), fsGroup
helps ensure that files created by different containers or users can be accessed by other containers in the same group. It’s especially useful in scenarios where multiple containers need to write to the same volume but are running under different users.
When you set runAsUser
, runAsGroup
, and fsGroup
, these values control how processes and files are managed inside the container:
runAsUser
determines the user ID of the processes running inside the container.runAsGroup
sets the primary group of those processes.fsGroup
sets the group ownership of mounted volumes, ensuring that the container has access to shared files through group permissions.Let’s say you have a container running a process as runAsUser: 1000
and runAsGroup: 1000
, with fsGroup: 2000
. The container’s process will:
1000
and group 1000
(i.e., the process will execute as a non-root user and group).2000
(as specified by fsGroup
), ensuring that files written to those volumes are accessible by other containers or users in group 2000
.This was a few lines of configurations at the end. What took too much time for me to realize was that the hostPath
volumes in Kubernetes do not respect the fsGroup
, runAsGroup
, or runAsUser
settings when mounted. The Kubernetes securityContext, including fsGroup
, does not change the ownership or permissions of files on hostPath
volumes. This is because hostPath
volumes directly mount directories from the host node’s filesystem, and Kubernetes does not modify the file ownership or permissions of the host’s file system when doing so.
Run and remotely access a Minikube Kubernetes cluster using the KVM on your computer
Read More