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.

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