Here we will mount the host file system into a windows pod on Kubernetes.
Alternatively, if you’re not trying to read/edit an existing host file, you can mount a brand new volume to the pod, which we will also show here.
Source code
Create Kubernetes cluster
Step one is to create or have access to a Kubernetes cluster with a Windows node.
One way to do this is to use AKS Engine, which sets up all the infrastructure for your Kubernetes cluster in Azure.
make-aks-engine-cluster.ps1
along with win-cluster.json
will do this for you.
All you need to provide is the subscription id you wish to deploy to:
$SUBSCRIPTION_ID='' $CLUSTER_NAME='win-cluster' $LOCATION='westus2' $API_MODEL='win-cluster.json' # Creates the resource group which will house your cluster az group create --subscription $SUBSCRIPTION_ID --location $LOCATION --name $CLUSTER_NAME # Creates an Azure Service Principal to let AKS-Engine deploy resources (your cluster) to your resource group $AZSP=az ad sp create-for-rbac --name win-cluster-service-principal --role="Owner" --scopes="/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$CLUSTER_NAME" -o json | ConvertFrom-Json $CLIENT_ID=$AZSP.appId $CLIENT_SECRET=$AZSP.password # Let azure permissions propogate before creating cluster Start-Sleep -Seconds 180 # Create a hostprocess capable kubernetes cluster using AKS-Engine .\aks-engine deploy ` --subscription-id $SUBSCRIPTION_ID ` --client-id $CLIENT_ID ` --client-secret $CLIENT_SECRET ` --resource-group $CLUSTER_NAME ` --dns-prefix $CLUSTER_NAME ` --location $LOCATION ` --api-model $API_MODEL ` --force-overwrite
{ "apiVersion": "vlabs", "properties": { "orchestratorProfile": { "orchestratorType": "Kubernetes", "orchestratorRelease": "1.23", "kubernetesConfig": { "networkPlugin": "azure", "containerRuntime": "containerd", "windowsContainerdURL": "https://github.com/kubernetes-sigs/sig-windows-tools/releases/download/windows-containerd-nightly/windows-containerd.tar.gz", "loadBalancerSku": "basic" } }, "masterProfile": { "count": 1, "vmSize": "Standard_D2_v2", "availabilityProfile": "AvailabilitySet", "platformUpdateDomainCount": 1 }, "agentPoolProfiles": [ { "name": "windowspool", "count": 1, "vmSize": "Standard_D8s_v3", "availabilityProfile": "VirtualMachineScaleSets", "osType": "Windows", "enableVMSSNodePublicIP": true } ], "windowsProfile": { "adminUsername": "azureuser", "adminPassword": "password1234$", "sshEnabled": true, "enableAutomaticUpdates": true, "WindowsPublisher": "microsoft-aks", "WindowsOffer": "aks-windows", "WindowsSku": "2019-datacenter-core-ctrd-2108", "imageVersion": "17763.2061.210830" }, "linuxProfile": { "adminUsername": "azureuser", "ssh": { "publicKeys": [ { "keyData": "" } ] } } } }
After execution you will hopefully see:
RDP and create host text file
Next we’ll RDP to the Windows agent node and create a text file.
This is just to demonstrate how the pod will be able to read and write files from/to the host.
To do this navigate to your Kubernetes agent node in Azure Portal:
And RDP using the credentials found in win-cluster.json
Finally, execute notepad hostfile.txt
and type a funny message:
Change the text file permissions
Update 04/10/2022: Check out our post on HostProcess pods where this step is no longer needed
Normal Windows pods can’t run as “privileged” pods, so we have to do this manual permissions step. There is a new type of Windows pod called “HostProcess” pods, which can do this by default without the permissions step, a post soon to follow about it.
For the time being, we have to give the right permissions:
icacls C:\users\azureuser /grant BUILTIN\Users:(OI)(CI)(F) /t
This command will give the directory C:\users\azureuser
and all files/directories in it the permissions necessary for the pod to be able to read and write files.
(OI)
and (CI)
means that all future files in this directory will have these permissions, and (F)
means full access. /t
means recursively. The BUILTIN\Users
is the group the pod will be a part of. Read more here if you’re interested.
Containerize an app which reads and writes to a file
Next we use Docker to containerize app.go
, which simply reads and writes to a given file:
docker build -t windowspodfilemount:v1.0.0 -f Dockerfile .
# Use golang image to build binary FROM golang:1.17 AS builder # Make a working directory WORKDIR /usr/local/app # Copy the source code into the container COPY src/ . # Build the app RUN go build app.go # Copy the app binary into the final container image FROM mcr.microsoft.com/windows/nanoserver:1809 COPY --from=builder /usr/local/app/app.exe \ /usr/local/bin/app.exe ENTRYPOINT ["/usr/local/bin/app.exe"]
package main import ( "fmt" "io/ioutil" "os" "time" ) func main() { hostFileToReadLocation := os.Args[1] hostFileToWriteLocation := os.Args[2] fmt.Printf("host file to read: %s\n", hostFileToReadLocation) fmt.Printf("host file to write: %s\n", hostFileToWriteLocation) // Read host file from inside the container! content, err := ioutil.ReadFile(hostFileToReadLocation) if err != nil { fmt.Printf("Error from reading: %v\n", err) } text := string(content) fmt.Println(text) // Write to host file from inside the container! f, err := os.OpenFile(hostFileToWriteLocation, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) if err != nil { fmt.Printf("Error opening file to write: %v\n", err) } if _, err = f.WriteString("Hello from the container!\n"); err != nil { fmt.Printf("Error writing to file: %v\n", err) } // Sleep time.Sleep(1 * time.Hour) }
Deploy the pod with host file mount
Next we deploy the app in a Windows pod with the host file system mounted as a volume.
.\kubectl --kubeconfig .\_output\win-cluster\kubeconfig\kubeconfig.westus2.json apply -f windowspodfilemount.yaml
apiVersion: v1 kind: Pod metadata: name: winpodfilemount spec: nodeSelector: kubernetes.io/os: windows containers: - name: winpodfilemount image: coolstercodes.azurecr.io/windowspodfilemount:v1.0.0 imagePullPolicy: Always args: ["C:\\hostfilemount\\hostfile.txt", "C:\\hostfilemount\\hostfile.txt"] volumeMounts: - name: hostfilemount mountPath: /hostfilemount volumes: - name: hostfilemount hostPath: path: /users/azureuser type: Directory
After deployment you should see something like:
And finally view the logs with:
.\kubectl --kubeconfig .\_output\win-cluster\kubeconfig\kubeconfig.westus2.json logs winpodfilemount
Verify
Now you can RDP back onto the Windows agent node and see the updated hostfile.txt
:
Alternative
If you’re just trying to write to the host and it doesn’t need to be an existing directory, you could alternatively use windowspodfilemount_alternative.yaml
, which creates a new directory on the host which the pod has full access to.
.\kubectl --kubeconfig .\_output\win-cluster\kubeconfig\kubeconfig.westus2.json apply -f windowspodfilemount_alternative.yaml
apiVersion: v1 kind: Pod metadata: name: winpodfilemount spec: nodeSelector: kubernetes.io/os: windows containers: - name: winpodfilemount image: coolstercodes.azurecr.io/windowspodfilemount:v1.0.0 imagePullPolicy: Always args: ["C:\\hostfilemount\\hostfile.txt", "C:\\hostfilemount\\hostfile.txt"] volumeMounts: - name: hostfilemount mountPath: /hostfilemount volumes: - name: hostfilemount hostPath: path: /new/host/directory type: DirectoryOrCreate
The “read” portion of the code will error out (because there’s nothing in this new directory), but the write will succeed:
.\kubectl --kubeconfig .\_output\win-cluster\kubeconfig\kubeconfig.westus2.json logs winpodfilemount
And finally you can verify by RDP’ing to the Windows agent node, that there is a new directory created by the pod:
Thank you very much for the post!!
I am trying to solve an issue where one of the pods needs to read the file from the host file system. I granted the permissions as mentioned but still, the pod could read the host files but can read the files that are created from the pod
This is a fluent-bit pod to tail the logs from C:\\var\\log\\containers and send the logs to a collector.
https://docs.microsoft.com/en-us/answers/questions/786486/mounted-hostfile-system-to-windows-container-to-re.html
Hi Vasudev!
Thank you for your comment! Let me take a look at this tonight and get back to you
Hi Vasudev,
If your pod still cannot read the host files you’ve mentioned, even with this command to the “/var/log/containers” directory: “icacls C:\users\azureuser /grant BUILTIN\Users:(OI)(CI)(F) /t” then what I would suggest is to use instead, a HostProcess Pod to deploy your app
https://coolstercodes.com/windows-hostprocess-pod-failed-to-get-application-name-from-commandine-failed-to-find-executable/
I can make a post to identify more specifically your situation soon, but in the meantime, here is a post about HostProcess pods and how to make one.
Even more specifically, in the “hostprocesspod.yaml” code segment, the part that relates to pod permissions on the host is
securityContext:
windowsOptions:
hostProcess: true
runAsUserName: “NT AUTHORITY\\Local service”
https://github.com/pjohnst5/CoolsterCodes/blob/8a819709f04b6dd9c154323d2c7422bc39767164/posts/windows-hostprocess-failed-to-get-application-name/hostprocesspod.yaml#L8
And then more documentation on the possible values of “runAsUserName” are here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-runasusername/
“Examples of acceptable values for the runAsUserName field: ContainerAdministrator, ContainerUser, NT AUTHORITY\NETWORK SERVICE, NT AUTHORITY\LOCAL SERVICE.”
Hope it helps!