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.

254 lines
7.8 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. *Note:* that if you have set multiple replicas, make sure your CSI driver has support for the `ReadWriteMany` accessMode.
  124. ## Expose the registry in the cluster
  125. Now that we have a registry `Pod` running, we can expose it as a Service:
  126. <!-- BEGIN MUNGE: EXAMPLE registry-svc.yaml -->
  127. ``` yaml
  128. apiVersion: v1
  129. kind: Service
  130. metadata:
  131. name: kube-registry
  132. namespace: kube-system
  133. labels:
  134. k8s-app: registry
  135. kubernetes.io/name: "KubeRegistry"
  136. spec:
  137. selector:
  138. k8s-app: registry
  139. ports:
  140. - name: registry
  141. port: 5000
  142. protocol: TCP
  143. ```
  144. <!-- END MUNGE: EXAMPLE registry-svc.yaml -->
  145. ## Expose the registry on each node
  146. Now that we have a running `Service`, we need to expose it onto each Kubernetes
  147. `Node` so that Docker will see it as `localhost`. We can load a `Pod` on every
  148. node by creating following daemonset.
  149. <!-- BEGIN MUNGE: EXAMPLE ../../saltbase/salt/kube-registry-proxy/kube-registry-proxy.yaml -->
  150. ``` yaml
  151. apiVersion: apps/v1
  152. kind: DaemonSet
  153. metadata:
  154. name: kube-registry-proxy
  155. namespace: kube-system
  156. labels:
  157. k8s-app: kube-registry-proxy
  158. version: v0.4
  159. spec:
  160. template:
  161. metadata:
  162. labels:
  163. k8s-app: kube-registry-proxy
  164. kubernetes.io/name: "kube-registry-proxy"
  165. version: v0.4
  166. spec:
  167. containers:
  168. - name: kube-registry-proxy
  169. image: gcr.io/google_containers/kube-registry-proxy:0.4
  170. resources:
  171. limits:
  172. cpu: 100m
  173. memory: 50Mi
  174. env:
  175. - name: REGISTRY_HOST
  176. value: kube-registry.kube-system.svc.cluster.local
  177. - name: REGISTRY_PORT
  178. value: "5000"
  179. ports:
  180. - name: registry
  181. containerPort: 80
  182. hostPort: 5000
  183. ```
  184. <!-- END MUNGE: EXAMPLE ../../saltbase/salt/kube-registry-proxy/kube-registry-proxy.yaml -->
  185. When modifying replication-controller, service and daemon-set definitions, take
  186. care to ensure *unique* identifiers for the rc-svc couple and the daemon-set.
  187. Failing to do so will have register the localhost proxy daemon-sets to the
  188. upstream service. As a result they will then try to proxy themselves, which
  189. will, for obvious reasons, not work.
  190. This ensures that port 5000 on each node is directed to the registry `Service`.
  191. You should be able to verify that it is running by hitting port 5000 with a web
  192. browser and getting a 404 error:
  193. ``` console
  194. $ curl localhost:5000
  195. 404 page not found
  196. ```
  197. ## Using the registry
  198. To use an image hosted by this registry, simply say this in your `Pod`'s
  199. `spec.containers[].image` field:
  200. ``` yaml
  201. image: localhost:5000/user/container
  202. ```
  203. Before you can use the registry, you have to be able to get images into it,
  204. though. If you are building an image on your Kubernetes `Node`, you can spell
  205. out `localhost:5000` when you build and push. More likely, though, you are
  206. building locally and want to push to your cluster.
  207. You can use `kubectl` to set up a port-forward from your local node to a
  208. running Pod:
  209. ``` console
  210. $ POD=$(kubectl get pods --namespace kube-system -l k8s-app=registry \
  211. -o template --template '{{range .items}}{{.metadata.name}} {{.status.phase}}{{"\n"}}{{end}}' \
  212. | grep Running | head -1 | cut -f1 -d' ')
  213. $ kubectl port-forward --namespace kube-system $POD 5000:5000 &
  214. ```
  215. Now you can build and push images on your local computer as
  216. `localhost:5000/yourname/container` and those images will be available inside
  217. your kubernetes cluster with the same name.