This document shows how to deploy a privileged daemonset in each node of Google Distributed Cloud to modify kubelet parameters to disable read-only ports.
Prerequisite
Make sure your Google Distributed Cloud is healthy before running the following patch script. This solution can be used to patch both admin clusters and user clusters. And it should work for all Google Distributed Cloud versions.
Save the following Daemonset YAML to your local file (e.g. patch.yaml)
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: onprem-node-patcher
namespace: kube-system
spec:
selector:
matchLabels:
name: onprem-node-patcher
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
name: onprem-node-patcher
spec:
tolerations:
- operator: Exists
volumes:
- name: host
hostPath:
path: /
hostPID: true
initContainers:
- name: read-only-patcher
image: "ubuntu"
env:
- name: KUBELET_READONLY_PORT
value: "0"
# Number of 1G hugepages. Update the value as desired.
command:
- /bin/bash
- -c
- |
set -xeuo pipefail
configfile="/host/var/lib/kubelet/config.yaml"
kubeletservice="/host/etc/systemd/system/kubelet.service"
# $1: The read-only port for the kubelet to serve on with no
# authentication/authorization (set to 0 to disable)
function set-readonly-port-in-config() {
[[ "$#" -eq 1 ]] || return
local readonlyport; readonlyport="$1"
local actual; actual="$(grep readOnlyPort "${configfile}")"
if [[ "${actual}" == "" ]]; then
echo "readOnlyPort: ${readonlyport}" >> "${configfile}"
else
sed -E -i 's/readOnlyPort: [0-9]+/readOnlyPort: 0/g' ${configfile}
fi
echo "Successfully append readOnlyPort: ${readonlyport} to ${configfile}"
}
sed -E -i 's/--read-only-port=[0-9]+/--read-only-port='"${KUBELET_READONLY_PORT}"'/g' ${kubeletservice}
[[ -f ${configfile} ]] && set-readonly-port-in-config "${KUBELET_READONLY_PORT}"
echo "Restarting kubelet..."
chroot /host nsenter -a -t1 -- systemctl daemon-reload
chroot /host nsenter -a -t1 -- systemctl restart kubelet.service
echo "Success!"
volumeMounts:
- name: host
mountPath: /host
resources:
requests:
memory: 5Mi
cpu: 5m
securityContext:
privileged: true
containers:
- image: gcr.io/google-containers/pause:3.2
name: pause
# Ensures that the pods will only run on the nodes having the correct
# label.
nodeSelector:
"kubernetes.io/os": "linux"
To re-enable the read-only port, manually edit the environment variable KUBELET_READONLY_PORT in the Daemonset YAML.
Once you save the changes, the daemonset will be re-run to modify the kubelet accordingly.
Caveats
This patch has the same lifecycle as your installed 3P apps. You can run it anytime as a day 2 operation. But it might not persist after you re-create the cluster. To make this change persistent, deploy this daemonset as a step in the Google Distributed Cloud post-initialization action.
After running once, the Kubelet config file should be modified and reloaded. You can safely run kubectl delete -f patch.yaml to clean up daemonset resources.
Anthos running on Windows does not currently support this patch.
The following metrics are lost for 1.13 and older cluster versions:
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-09-04 UTC."],[[["\u003cp\u003eThis guide outlines how to deploy a privileged daemonset within Google Distributed Cloud to modify kubelet parameters, specifically disabling read-only ports on both admin and user clusters.\u003c/p\u003e\n"],["\u003cp\u003eThe provided YAML configuration file (\u003ccode\u003epatch.yaml\u003c/code\u003e) contains the daemonset definition, which includes an init container to set the \u003ccode\u003ereadOnlyPort\u003c/code\u003e to 0 and modify the kubelet service, effectively disabling the read-only port.\u003c/p\u003e\n"],["\u003cp\u003eTo apply the patch, users should use the \u003ccode\u003ekubectl apply\u003c/code\u003e command with the \u003ccode\u003epatch.yaml\u003c/code\u003e file and the appropriate kubeconfig for either the admin or user cluster.\u003c/p\u003e\n"],["\u003cp\u003eRestoring the read-only port functionality requires manually editing the \u003ccode\u003eKUBELET_READONLY_PORT\u003c/code\u003e environment variable within the \u003ccode\u003epatch.yaml\u003c/code\u003e file and reapplying the daemonset.\u003c/p\u003e\n"],["\u003cp\u003eThis patch is compatible with all Google Distributed Cloud versions but it does not persist through cluster recreation, and it does not work with Anthos running on Windows, while also impacting certain metrics for clusters version 1.13 and older.\u003c/p\u003e\n"]]],[],null,["# Disable Kubelet readonly port\n\n\u003cbr /\u003e\n\nOverview\n--------\n\nThis document shows how to deploy a privileged daemonset in each node of Google Distributed Cloud to modify kubelet parameters to disable read-only ports.\n\nPrerequisite\n------------\n\nMake sure your Google Distributed Cloud is healthy before running the following patch script. This solution can be used to patch both admin clusters and user clusters. And it should work for all Google Distributed Cloud versions.\n\nSave the following Daemonset YAML to your local file (e.g. patch.yaml)\n----------------------------------------------------------------------\n\n```\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n name: onprem-node-patcher\n namespace: kube-system\nspec:\n selector:\n matchLabels:\n name: onprem-node-patcher\n updateStrategy:\n type: RollingUpdate\n template:\n metadata:\n labels:\n name: onprem-node-patcher\n spec:\n tolerations:\n - operator: Exists\n volumes:\n - name: host\n hostPath:\n path: /\n hostPID: true\n initContainers:\n - name: read-only-patcher\n image: \"ubuntu\"\n env:\n - name: KUBELET_READONLY_PORT\n value: \"0\"\n # Number of 1G hugepages. Update the value as desired.\n command:\n - /bin/bash\n - -c\n - |\n set -xeuo pipefail\n configfile=\"/host/var/lib/kubelet/config.yaml\"\n kubeletservice=\"/host/etc/systemd/system/kubelet.service\"\n # $1: The read-only port for the kubelet to serve on with no\n # authentication/authorization (set to 0 to disable)\n function set-readonly-port-in-config() {\n [[ \"$#\" -eq 1 ]] || return\n local readonlyport; readonlyport=\"$1\"\n local actual; actual=\"$(grep readOnlyPort \"${configfile}\")\"\n if [[ \"${actual}\" == \"\" ]]; then\n echo \"readOnlyPort: ${readonlyport}\" \u003e\u003e \"${configfile}\"\n else\n sed -E -i 's/readOnlyPort: [0-9]+/readOnlyPort: 0/g' ${configfile}\n fi\n echo \"Successfully append readOnlyPort: ${readonlyport} to ${configfile}\"\n }\n sed -E -i 's/--read-only-port=[0-9]+/--read-only-port='\"${KUBELET_READONLY_PORT}\"'/g' ${kubeletservice}\n [[ -f ${configfile} ]] && set-readonly-port-in-config \"${KUBELET_READONLY_PORT}\"\n echo \"Restarting kubelet...\"\n chroot /host nsenter -a -t1 -- systemctl daemon-reload\n chroot /host nsenter -a -t1 -- systemctl restart kubelet.service\n echo \"Success!\"\n volumeMounts:\n - name: host\n mountPath: /host\n resources:\n requests:\n memory: 5Mi\n cpu: 5m\n securityContext:\n privileged: true\n containers:\n - image: gcr.io/google-containers/pause:3.2\n name: pause\n # Ensures that the pods will only run on the nodes having the correct\n # label.\n nodeSelector:\n \"kubernetes.io/os\": \"linux\"\n```\n\nPatch on the admin cluster\n--------------------------\n\n```\n kubectl apply -f patch.yaml \\\n --kubeconfig ADMIN_CLUSTER_KUBECONFIG\n```\n\nPatch on the user cluster\n-------------------------\n\n```\n kubectl apply -f patch.yaml \\\n --kubeconfig USER_CLUSTER_KUBECONFIG\n```\n\nRestore\n-------\n\n- To re-enable the read-only port, manually edit the environment variable `KUBELET_READONLY_PORT` in the Daemonset YAML.\n\n- Once you save the changes, the daemonset will be re-run to modify the kubelet accordingly.\n\nCaveats\n-------\n\n- This patch has the same lifecycle as your installed 3P apps. You can run it anytime as a day 2 operation. But it might not persist after you re-create the cluster. To make this change persistent, deploy this daemonset as a step in the Google Distributed Cloud post-initialization action.\n\n- After running once, the Kubelet config file should be modified and reloaded. You can safely run `kubectl delete -f patch.yaml` to clean up daemonset resources.\n\n- Anthos running on Windows does not currently support this patch.\n\n- The following metrics are lost for 1.13 and older cluster versions:\n\n - [Resource utilization metrics](/anthos/clusters/docs/on-prem/1.14/metrics-anthos#find_a_metric)\n - [Kubelet metrics](/anthos/clusters/docs/on-prem/1.14/metrics-anthos#find_a_metric)"]]