When kops created the VMs (EC2 instances), the first thing it did was to execute nodeup. It, in turn, installed a few packages. It made sure that Docker, Kubelet, and Protokube are up and running.
Docker
Docker runs containers. It would be hard for me to imagine that you don’t know what Docker does, so we’ll skip to the next in line.
Kubelet
Kubelet is Kubernetes’ node agent. It runs on every node of a cluster, and its primary purpose is to run Pods. Or, to be more precise, it ensures that the containers described in PodSpecs are running as long as they are healthy. It primarily gets the information about the Pods it should run through Kubernetes’ API server. As an alternative, it can get the info through files, HTTP endpoints, and HTTP servers.
Protokube
Unlike Docker and Kubelet, Protokube is specific to kops. Its primary responsibilities are to discover master disks, to mount them, and to create manifests. Some of those manifests are used by Kubelet to create system-level Pods and to make sure that they are always running.
Besides starting the containers defined through Pods in the manifests (created by Protokube), Kubelet also tries to contact the API server which, eventually, is also started by it. Once the connection is established, Kubelet registers the node where it is running.
All three packages are running on all the nodes, no matter whether they are masters or workers.