Having the ability to containerize your Windows based application and running them on Kubernetes is a great options, specially for companies who are not looking forward to modernize their application using a cross platforms frameworks.
While containerizing Windows based application is pretty much easy, being able to control the time zone of the windows based nodes is kind of tricky specially when using Azure Kubernetes Services (AKS), or Amazon EKS. hosted on a different region.
lets go through one of the options we have to overcome this issue.
The idea is to create a K8s DaemonSet which is going to ensure a specific pod to be deployed to each and every node that exists or being added to the cluster, that pod will simply connect to its host node and set the timezone to your proffered one.
Preparing a docker image for you the DaemonSet Pod
First you need to have Docker Desktop downloaded and installed on your development machine.
https://www.docker.com/products/docker-desktop
Make sure you switch to windows based engine. now create an empty folder in which we are going to use to build our image, lets name it TimeZoneImage.
we are going to need a tool which will help us ssh inside the node from the pod, one advantage plink is the ability to automate passing in the username and password of an SSH session, download plink.exe 64bits from the link below and store it inside TimeZoneImage folder.
https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html
we need to pass in a script which will be executed remotely on the server so create a new file bat file lets call it script.bat
script.bat
powershell Set-TimeZone -Name '#TimeZone#'; echo "Done execting inside the Node!...";echo "Changing Time Zone to: #TimeZone#";
This will simply set the time zone to your TimeZone Env Variable.
Next we need a file to act as an entrypoint for our container, lets create that file and call it start.ps1
start.ps1
echo "Start Plink with Node $env:nodeIP"
$filePath = 'script.bat'
$tempFilePath = "$env:TEMP\$($filePath | Split-Path -Leaf)"
$find = '#TimeZone#'
$replace = $env:timezone
(Get-Content -Path $filePath) -replace $find, $replace | Add-Content -Path $tempFilePath
Remove-Item -Path $filePath
Move-Item -Path $tempFilePath -Destination $filePath
do{
echo $("Setting TimeZone to Arab Time Zone at " + $(Get-Date).ToString())
echo y | c:\\plink.exe $env:nodeIP -l $env:user -pw $env:pwd -m script.bat
echo "Done Setting TimeZone for this round!..."
sleep 1440
}while($true)
Echo "Done Plink"
Next the DockerFile would look like this
FROM mcr.microsoft.com/windows/servercore:ltsc2019
COPY plink.exe /
COPY script.bat /
COPY start.ps1 /
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; Set-ExecutionPolicy Unrestricted -Force;"]
ENTRYPOINT ["powershell.exe", "c:\\start.ps1"]
The folder should look like this

Open power-shell and from inside the folder run the following command to build the image, tag it and push it to your favourite container register, (In this case I will use Azure Container Registry)
docker build .
docker tag <yourimage> <youracr>.azurecr.io/<yourimagename>
docker push <yourimage> <youracr>.azurecr.io/<yourimagename>
once done we are ready to create our DaemonSet
https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
A DaemonSet ensures
that all (or some) Nodes run a copy of a Pod. As nodes are added to the cluster, Pods are added to them. As nodes are removed from the cluster, those Pods are garbage collected. Deleting a DaemonSet will clean up the Pods it created.
User the following Yaml file to deploy DaemonSet:
apiVersion: apps/v1
kind: DaemonSet
metadata:
namespace: kube-system
name: wintimezonedaemon-ds
spec:
selector:
matchLabels:
name: wintimezonedaemon-ds
template:
metadata:
labels:
name: wintimezonedaemon-ds
spec:
nodeSelector:
"beta.kubernetes.io/os": windows
containers:
- name: wintimezonedaemon
env:
- name: nodeIP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: timezone
value: <yourpreferedtimezone>
- name: user
value: <your-vmss-or-node-user>
- name: pwd
value: <your-vmss-or-node-password>
image: <youracr>.azurecr.io/<yourimagename>:latest
resources:
limits:
cpu: 300m
memory: 400M
requests:
cpu: 150m
memory: 200M
Note the environment variables, the first one is to pass in the NodeIP to the pod which is going to be used to communicate with the node, the second env variable is where you provide your preferred time zone the third and fourth env variables are basically your windows node username and password if you need to reset this you can go to the VMSS on azure portal (Assuming AK) and choose “Reset Password”, .
once done you can simply execute the following command to create your DaemonSet
kubectl create -f daemonset.yaml
Check Github for the source code.
https://github.com/mohaom/TimeZoneImage
for a ready made image use the following:
https://hub.docker.com/r/omarse/windowstimezoner
or directly pull using
docker pull omarse/windowstimezoner
docker pull omarse/windowstimezoner:latest