You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
7.3 KiB

  1. # Private Docker Registry in Kubernetes
  2. Kubernetes offers an optional private Docker registry addon, which you can turn
  3. on when you bring up a cluster or install later. This gives you a place to
  4. store truly private Docker images for your cluster.
  5. ## How it works
  6. The private registry runs as a `Pod` in your cluster. It does not currently
  7. support SSL or authentication, which triggers Docker's "insecure registry"
  8. logic. To work around this, we run a proxy on each node in the cluster,
  9. exposing a port onto the node (via a hostPort), which Docker accepts as
  10. "secure", since it is accessed by `localhost`.
  11. ## Turning it on
  12. Some cluster installs (e.g. GCE) support this as a cluster-birth flag. The
  13. `ENABLE_CLUSTER_REGISTRY` variable in `cluster/gce/config-default.sh` governs
  14. whether the registry is run or not. To set this flag, you can specify
  15. `KUBE_ENABLE_CLUSTER_REGISTRY=true` when running `kube-up.sh`. If your cluster
  16. does not include this flag, the following steps should work. Note that some of
  17. this is cloud-provider specific, so you may have to customize it a bit.
  18. ### Make some storage
  19. The primary job of the registry is to store data. To do that we have to decide
  20. where to store it. For cloud environments that have networked storage, we can
  21. use Kubernetes's `PersistentVolume` abstraction. The following template is
  22. expanded by `salt` in the GCE cluster turnup, but can easily be adapted to
  23. other situations:
  24. ```yaml
  25. kind: PersistentVolume
  26. apiVersion: v1
  27. metadata:
  28. name: kube-system-kube-registry-pv
  29. spec:
  30. {% if pillar.get('cluster_registry_disk_type', '') == 'gce' %}
  31. capacity:
  32. storage: {{ pillar['cluster_registry_disk_size'] }}
  33. accessModes:
  34. - ReadWriteOnce
  35. gcePersistentDisk:
  36. pdName: "{{ pillar['cluster_registry_disk_name'] }}"
  37. fsType: "ext4"
  38. {% endif %}
  39. ```
  40. If, for example, you wanted to use NFS you would just need to change the
  41. `gcePersistentDisk` block to `nfs`. See
  42. [here](https://kubernetes.io/docs/concepts/storage/volumes/) for more details on volumes.
  43. Note that in any case, the storage (in the case the GCE PersistentDisk) must be
  44. created independently - this is not something Kubernetes manages for you (yet).
  45. ### I don't want or don't have persistent storage
  46. If you are running in a place that doesn't have networked storage, or if you
  47. just want to kick the tires on this without committing to it, you can easily
  48. adapt the `ReplicationController` specification below to use a simple
  49. `emptyDir` volume instead of a `persistentVolumeClaim`.
  50. ## Claim the storage
  51. Now that the Kubernetes cluster knows that some storage exists, you can put a
  52. claim on that storage. As with the `PersistentVolume` above, you can start
  53. with the `salt` template:
  54. ```yaml
  55. kind: PersistentVolumeClaim
  56. apiVersion: v1
  57. metadata:
  58. name: kube-registry-pvc
  59. namespace: kube-system
  60. spec:
  61. accessModes:
  62. - ReadWriteOnce
  63. resources:
  64. requests:
  65. storage: {{ pillar['cluster_registry_disk_size'] }}
  66. ```
  67. This tells Kubernetes that you want to use storage, and the `PersistentVolume`
  68. you created before will be bound to this claim (unless you have other
  69. `PersistentVolumes` in which case those might get bound instead). This claim
  70. gives you the right to use this storage until you release the claim.
  71. ## Run the registry
  72. Now we can run a Docker registry:
  73. ```yaml
  74. apiVersion: v1
  75. kind: ReplicationController
  76. metadata:
  77. name: kube-registry-v0
  78. namespace: kube-system
  79. labels:
  80. k8s-app: registry
  81. version: v0
  82. spec:
  83. replicas: 1
  84. selector:
  85. k8s-app: registry
  86. version: v0
  87. template:
  88. metadata:
  89. labels:
  90. k8s-app: registry
  91. version: v0
  92. spec:
  93. containers:
  94. - name: registry
  95. image: registry:2
  96. resources:
  97. limits:
  98. cpu: 100m
  99. memory: 100Mi
  100. env:
  101. - name: REGISTRY_HTTP_ADDR
  102. value: :5000
  103. - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
  104. value: /var/lib/registry
  105. volumeMounts:
  106. - name: image-store
  107. mountPath: /var/lib/registry
  108. ports:
  109. - containerPort: 5000
  110. name: registry
  111. protocol: TCP
  112. volumes:
  113. - name: image-store
  114. persistentVolumeClaim:
  115. claimName: kube-registry-pvc
  116. ```
  117. *Note:* that if you have set multiple replicas, make sure your CSI driver has support for the `ReadWriteMany` accessMode.
  118. ## Expose the registry in the cluster
  119. Now that we have a registry `Pod` running, we can expose it as a Service:
  120. ```yaml
  121. apiVersion: v1
  122. kind: Service
  123. metadata:
  124. name: kube-registry
  125. namespace: kube-system
  126. labels:
  127. k8s-app: registry
  128. kubernetes.io/name: "KubeRegistry"
  129. spec:
  130. selector:
  131. k8s-app: registry
  132. ports:
  133. - name: registry
  134. port: 5000
  135. protocol: TCP
  136. ```
  137. ## Expose the registry on each node
  138. Now that we have a running `Service`, we need to expose it onto each Kubernetes
  139. `Node` so that Docker will see it as `localhost`. We can load a `Pod` on every
  140. node by creating following daemonset.
  141. ```yaml
  142. apiVersion: apps/v1
  143. kind: DaemonSet
  144. metadata:
  145. name: kube-registry-proxy
  146. namespace: kube-system
  147. labels:
  148. k8s-app: kube-registry-proxy
  149. version: v0.4
  150. spec:
  151. template:
  152. metadata:
  153. labels:
  154. k8s-app: kube-registry-proxy
  155. kubernetes.io/name: "kube-registry-proxy"
  156. version: v0.4
  157. spec:
  158. containers:
  159. - name: kube-registry-proxy
  160. image: gcr.io/google_containers/kube-registry-proxy:0.4
  161. resources:
  162. limits:
  163. cpu: 100m
  164. memory: 50Mi
  165. env:
  166. - name: REGISTRY_HOST
  167. value: kube-registry.kube-system.svc.cluster.local
  168. - name: REGISTRY_PORT
  169. value: "5000"
  170. ports:
  171. - name: registry
  172. containerPort: 80
  173. hostPort: 5000
  174. ```
  175. When modifying replication-controller, service and daemon-set definitions, take
  176. care to ensure *unique* identifiers for the rc-svc couple and the daemon-set.
  177. Failing to do so will have register the localhost proxy daemon-sets to the
  178. upstream service. As a result they will then try to proxy themselves, which
  179. will, for obvious reasons, not work.
  180. This ensures that port 5000 on each node is directed to the registry `Service`.
  181. You should be able to verify that it is running by hitting port 5000 with a web
  182. browser and getting a 404 error:
  183. ```ShellSession
  184. $ curl localhost:5000
  185. 404 page not found
  186. ```
  187. ## Using the registry
  188. To use an image hosted by this registry, simply say this in your `Pod`'s
  189. `spec.containers[].image` field:
  190. ```yaml
  191. image: localhost:5000/user/container
  192. ```
  193. Before you can use the registry, you have to be able to get images into it,
  194. though. If you are building an image on your Kubernetes `Node`, you can spell
  195. out `localhost:5000` when you build and push. More likely, though, you are
  196. building locally and want to push to your cluster.
  197. You can use `kubectl` to set up a port-forward from your local node to a
  198. running Pod:
  199. ```ShellSession
  200. $ POD=$(kubectl get pods --namespace kube-system -l k8s-app=registry \
  201. -o template --template '{{range .items}}{{.metadata.name}} {{.status.phase}}{{"\n"}}{{end}}' \
  202. | grep Running | head -1 | cut -f1 -d' ')
  203. $ kubectl port-forward --namespace kube-system $POD 5000:5000 &
  204. ```
  205. Now you can build and push images on your local computer as
  206. `localhost:5000/yourname/container` and those images will be available inside
  207. your kubernetes cluster with the same name.