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