{"id":771,"date":"2020-08-06T15:30:00","date_gmt":"2020-08-06T15:30:00","guid":{"rendered":"https:\/\/www.geekmungus.co.uk\/?p=771"},"modified":"2022-11-05T10:53:18","modified_gmt":"2022-11-05T10:53:18","slug":"microk8s-kubernetes-raspberry-pi-ubuntu-linux-basic-setup-guide-part-4-image-repositories","status":"publish","type":"post","link":"https:\/\/geekmungus.co.uk\/?p=771","title":{"rendered":"MicroK8s (Kubernetes) &#8211; Raspberry Pi Ubuntu Linux Basic Setup Guide &#8211; Part 4 (Image Repositories)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/microk8s.io\/docs\/registry-images\">https:\/\/microk8s.io\/docs\/registry-images<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So images. A container is based on an image. You can pull these images in from the outside world, e.g. from a Public, Private registry, or from the built-in registry.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For this copy the &#8220;hello-python&#8221; directory we created in Part 2 into one called &#8220;hello-python3&#8221;, you can delete the .tar file in there for now, its not needed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Push Image into Kubernetes Image Repository<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So in the earlier steps, we basically injected the image straight into the Kubernetes image cache, so not using the built-in registry.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now we\u2019ll do the same but this time working with the Kubernetes registry, so firstly lets enable it if not already done:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>microk8s enable registry<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Right, so the registry is now available at <strong>localhost:32000<\/strong>, when we upload an image we need to tag it accordingly with <strong>localhost:32000\/your-image-name<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So let\u2019s inject the image we used before, but this time tag with another name:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker build . -t localhost:32000\/hello-python:registry<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Build the image:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@k8s-master:\/home\/ubuntu\/application\/hello-python\/app# docker build . -t localhost:32000\/hello-python:registry\n\nSending build context to Docker daemon  99.71MB (updates\u2026.)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Wait for the image to upload into the docker images library.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker images\n\nroot@k8s-master:\/home\/ubuntu\/application\/hello-python\/app# docker images\n\nREPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE\n\nlocalhost:32000\/hello-python   registry            03e7eaf7b301        13 seconds ago      1.77GB\n\nhello-python                   local               a5aba8ae8f7d        38 hours ago        874MB\n\npython                         3.7                 42cd7c61ce0e        2 days ago          863MB<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now we want to push this into the Kubernetes registry:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker push localhost:32000\/hello-python\n\nroot@k8s-master:\/home\/ubuntu\/application\/hello-python\/app# docker push localhost:32000\/hello-python\n\nThe push refers to repository &#91;localhost:32000\/hello-python]\n\n32963f3bbf70: Pushing &#91;==================>                                ]  3.899MB\/10.74MB\n\n0059fe46108e: Pushing &#91;>                                                  ]  9.997MB\/897.8MB\n\n8c51df724705: Pushed\n\nfc5072a676ca: Pushing &#91;==========================>                        ]  3.773MB\/7.235MB\n\nbfc730b5d6a1: Pushed\n\nc2047c5c6a3d: Pushing &#91;===>                                               ]  6.636MB\/86.97MB\n\nad87fe9fbf86: Pushing &#91;===============>                                   ]  5.625MB\/18.08MB\n\nde08a49275ea: Waiting\n\ne6eb43d220d2: Waiting\n\na76bedae40bf: Waiting\n\n9184b9a70c9e: Waiting\n\n9276caf83dc1: Waiting<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At this point the image is then within the Kubernetes image repository and ready to be used in your application deployments.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Deploy Container using Registry Image<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So lets create a cheeky application, create a deployment.yaml and service.yaml as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1\n\nkind: Deployment\n\nmetadata:\n\n  name: hello-python3\n\nspec:\n\n  selector:\n\n    matchLabels:\n\n      app: hello-python3\n\n  replicas: 1\n\n  template:\n\n    metadata:\n\n      labels:\n\n        app: hello-python3\n\n    spec:\n\n      containers:\n\n      - name: hello-python3\n\n        image: localhost:32000\/hello-python:registry\n\n        ports:\n\n        - containerPort: 5000<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And an service.yaml:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\n\nkind: Service\n\nmetadata:\n\n  name: hello-python3-service\n\nspec:\n\n  selector:\n\n    app: hello-python3\n\n  ports:\n\n  - port: 8080\n\n    targetPort: 5000\n\n  type: LoadBalancer<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then deploy the application and service with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f deployment.yaml\n\nkubectl apply -f service.yaml\n\nroot@k8s-master:\/home\/ubuntu\/application\/hello-python3\/app# kubectl get pods -o wide\n\nNAME                                  READY   STATUS             RESTARTS   AGE   IP           NODE            NOMINATED NODE   READINESS GATES\n\nhello-python-6bfc96894d-qhv8h         1\/1     Running            1          38h   10.1.54.21   k8s-master      &lt;none>           &lt;none>\n\nhello-python-redux-7849b9b844-55sxb   1\/1     Running            0          19h   10.1.54.40   k8s-master      &lt;none>           &lt;none>\n\nhello-python3-5fdcb55ccd-dvpnx        0\/1     ImagePullBackOff   0          47s   10.1.49.2    k8s-worker-02   &lt;none>           &lt;none><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Oh look, we have an error, excellent. So let&#8217;s look at why this happened.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So so far, we\u2019ve deployed the image registry on the master node, the worker nodes have no configuration for them to reach this registry at the moment. Now if we were to have built and pushed this registry in when we would have only had one node, then the only place the pod could have run would have been on the master node, which can get to the Kubernetes image registry. To fix this we need to complete the next section, as you can see the \u201cImagePullBackOff\u201d basically means that the pods has been scheduled to a node which is unable to download the image.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If we look at the log for the pod: &#8220;hello-python3-5fdcb55ccd-dvpnx&#8221; we see:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@k8s-master:\/home\/ubuntu\/application\/hello-python3\/app# kubectl logs hello-python3-7b6df7676b-sp2mf\n\nError from server (BadRequest): container \"hello-python3\" in pod \"hello-python3-7b6df7676b-sp2mf\" is waiting to start: image can't be pulled<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So we make the change to the deployment.yaml:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1\n\nkind: Deployment\n\nmetadata:\n\n  name: hello-python3\n\nspec:\n\n  selector:\n\n    matchLabels:\n\n      app: hello-python3\n\n  replicas: 1\n\n  template:\n\n    metadata:\n\n      labels:\n\n        app: hello-python3\n\n    spec:\n\n      containers:\n\n      - name: hello-python3\n\n        image: 192.168.1.164:32000\/hello-python:registry\n\n        ports:\n\n        - containerPort: 5000<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And then deploy again with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f deployment.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We still are having problems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If we run this on the node where the pod is trying to start:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -f \/var\/log\/syslog  | grep hello<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We see:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Aug  2 14:48:49 k8s-worker-02 microk8s.daemon-kubelet&#91;1324]: E0802 14:48:49.023084    1324 pod_workers.go:191] Error syncing pod 9490b872-87cd-48c9-90b6-952c7dc7b452 (\"hello-python3-7b6df7676b-vt4v5_default(9490b872-87cd-48c9-90b6-952c7dc7b452)\"), skipping: failed to \"StartContainer\" for \"hello-python3\" with ErrImagePull: \"rpc error: code = Unknown desc = failed to pull and unpack image \\\"192.168.1.164:32000\/hello-python:registry\\\": failed to resolve reference \\\"192.168.1.164:32000\/hello-python:registry\\\": failed to do request: Head \\\"https:\/\/192.168.1.164:32000\/v2\/hello-python\/manifests\/registry\\\": http: server gave HTTP response to HTTPS client\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So this exact error is described here:<a rel=\"noreferrer noopener\" href=\"https:\/\/www.google.com\/url?q=https%3A%2F%2Fmicrok8s.io%2Fdocs%2Fregistry-private&amp;sa=D&amp;sntz=1&amp;usg=AFQjCNH28YHOhs3FkS-FTSAg07vD6VhZeQ\" target=\"_blank\"> https:\/\/microk8s.io\/docs\/registry-private<\/a> under the section \u201cConfiguring MicroK8s\u201d. We need to make some changes to the configuration of the MicroK8s nodes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Allowing Insecure Registry<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Edit the file: <strong>\/var\/snap\/microk8s\/current\/args\/containerd-template.toml<\/strong> on ONLY the worker nodes, so in our case <strong>k8s-worker-01<\/strong> and <strong>k8s-worker-02<\/strong>, right at the bottom of the file look for the following section:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>[plugins] -&gt; [plugins.&#8221;io.containerd.grpc.v1.cri&#8221;.registry] -&gt; [plugins.&#8221;io.containerd.grpc.v1.cri&#8221;.registry.mirrors]:<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a new section underneath to match the IP address of your master node where the image repository lies for example the below, in my case the k8s-master node is on 192.168.1.164.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;plugins.\"io.containerd.grpc.v1.cri\".registry.mirrors.\"192.168.1.164:32000\"]\n\n          endpoint = &#91;\"http:\/\/192.168.1.164:32000\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Microk8s documentation then talks about just restarting microk8s with a \u201cmicrok8s stop\u201d followed by a \u201cmicrok8s start\u201d, however I found this was not enough, so rebooted the worker and master nodes, once restarted, i attempted the deployment again:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f deployment.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then a quick check on the progress:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@k8s-master:\/home\/ubuntu\/application\/hello-python3\/app# kubectl get pods -o wide\n\nNAME                                  READY   STATUS    RESTARTS   AGE     IP           NODE            NOMINATED NODE   READINESS GATES\n\nhello-python-6bfc96894d-qhv8h         1\/1     Running   4          40h     10.1.54.63   k8s-master      &lt;none>           &lt;none>\n\nhello-python-redux-7849b9b844-55sxb   1\/1     Running   3          21h     10.1.54.59   k8s-master      &lt;none>           &lt;none>\n\nhello-python3-7b6df7676b-qk2mq        1\/1     Running   0          8m11s   10.1.81.4    k8s-worker-01   &lt;none>           &lt;none><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As you can see it is there, the pod is running on the k8s-worker-01 node, lets have a quick look at the logs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat \/var\/log\/syslog | grep hello-python3<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now this time we see all is well:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Aug  2 15:11:21 k8s-worker-01 microk8s.daemon-containerd&#91;1303]: time=\"2020-08-02T15:11:21.254616306+01:00\" level=info msg=\"CreateContainer within sandbox \\\"8f4012258d385007f7a6523b627ca1fa27f4ea21d01e3ac6bf3024b4ffe1fca0\\\" for container &amp;ContainerMetadata{Name:hello-python3,Attempt:0,}\"\n\nAug  2 15:11:25 k8s-worker-01 microk8s.daemon-containerd&#91;1303]: time=\"2020-08-02T15:11:25.561390309+01:00\" level=info msg=\"CreateContainer within sandbox \\\"8f4012258d385007f7a6523b627ca1fa27f4ea21d01e3ac6bf3024b4ffe1fca0\\\" for &amp;ContainerMetadata{Name:hello-python3,Attempt:0,} returns container id \\\"bc93c29f081139990e98558d065e6b459fe26b34e3f17e49b7c7ecbc3768785e\\\"\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now lets create the service to access the application, so back on the Master node, we run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f service.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And have a quick check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@k8s-master:\/home\/ubuntu\/application\/hello-python3\/app# kubectl get services -o wide\n\nNAME                         TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)          AGE   SELECTOR\n\nhello-python3-service        LoadBalancer   10.152.183.149   192.168.1.22   8080:31272\/TCP   16s   app=hello-python3\n\nkubernetes                   ClusterIP      10.152.183.1     &lt;none>         443\/TCP          40h   &lt;none><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Yes, there it is:<a rel=\"noreferrer noopener\" href=\"http:\/\/www.google.com\/url?q=http%3A%2F%2F192.168.1.22%3A8080&amp;sa=D&amp;sntz=1&amp;usg=AFQjCNH0PIvbg5lJ2LM6ihS-0-pyORXeGA\" target=\"_blank\"> http:\/\/192.168.1.22:8080<\/a>, so lets try to access it:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.geekmungus.co.uk\/wp-content\/uploads\/2021\/08\/image-1.png\" alt=\"\" class=\"wp-image-773\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Good stuff, we\u2019ve done it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Doing it All Again! Well Why Not!?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lets run this command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>microk8s kubectl create deployment hello-python4 --image=192.168.1.164:32000\/hello-python:registry<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That will just create a deployment of that image as a new container and then schedule it on one of the worker nodes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@k8s-master:\/home\/ubuntu\/application\/hello-python3\/app# kubectl get pods -o wide\n\nNAME                                  READY   STATUS    RESTARTS   AGE   IP           NODE            NOMINATED NODE   READINESS GATES\n\nhello-python-6bfc96894d-qhv8h         1\/1     Running   4          40h   10.1.54.63   k8s-master      &lt;none>           &lt;none>\n\nhello-python-redux-7849b9b844-55sxb   1\/1     Running   3          21h   10.1.54.59   k8s-master      &lt;none>           &lt;none>\n\nhello-python3-7b6df7676b-qk2mq        1\/1     Running   0          13m   10.1.81.4    k8s-worker-01   &lt;none>           &lt;none>\n\nhello-python4-55bdb58666-sk8wg        1\/1     Running   0          5s    10.1.81.5    k8s-worker-01   &lt;none>           &lt;none><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Cool, there it is \u201chello-python4-55bdb58666-sk8wg\u201d working as expected on the k8s-worker-01 node, thats good that proves that the registry is working.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Verifying the Registry Image is Used<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Okay so lets copy the existing directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cp -r hello-python hello-python5<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now within there, if there is an image .tar file delete it, we don\u2019t need it anymore.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s edit the application to show we are getting a new image.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd hello-python5\/app<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Edit the \u201cmain.py\u201d, and add something to the line saying \u201cHello from Python\u201d, e.g. \u201cThis is a test page using Hello-python5 application!\u201d<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Build the image, and tag it as the image name for the Kubernetes image registry when put into the docker image library.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker build . -t localhost:32000\/hello-python5:registry\n\ndocker images\n\nroot@k8s-master:\/home\/ubuntu\/application\/hello-python5\/app# docker images\n\nREPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE\n\nlocalhost:32000\/hello-python5   registry            e699191159f2        6 seconds ago       874MB<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Okay so now get docker to push it into the Kubernetes image library.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker push localhost:32000\/hello-python5<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now edit the deployment.yaml and service.yaml, and where you have \u201chello-python3\u2026\u201d change it to \u201chello-python5\u201d, including the image location in the deployment.yaml file, so we make sure we use our new image!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So now deploy the service and deployment with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f deployment.yaml\n\nkubectl apply -f service.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If we run a quick: \u201ctail -f \/var\/log\/syslog | grep hello-python5\u201d we can see the container image being deployed and started.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Aug  2 15:44:32 k8s-worker-02 microk8s.daemon-containerd&#91;1300]: time=\"2020-08-02T15:44:32.322560841+01:00\" level=info msg=\"PullImage \\\"192.168.1.164:32000\/hello-python5:registry\\\" returns image reference \\\"sha256:e699191159f229e8e6aeae167a32c37a830d7c238182ee3f8825e8d5000f0d3d\\\"\"\n\nAug  2 15:44:32 k8s-worker-02 microk8s.daemon-containerd&#91;1300]: time=\"2020-08-02T15:44:32.328968944+01:00\" level=info msg=\"CreateContainer within sandbox \\\"35c4ee9ebdd4b90744f276d066ba7c75abe1f856cfe6e2e795100c39411789f4\\\" for container &amp;ContainerMetadata{Name:hello-python5,Attempt:0,}\"\n\nAug  2 15:44:33 k8s-worker-02 microk8s.daemon-containerd&#91;1300]: time=\"2020-08-02T15:44:33.337282018+01:00\" level=info msg=\"CreateContainer within sandbox \\\"35c4ee9ebdd4b90744f276d066ba7c75abe1f856cfe6e2e795100c39411789f4\\\" for &amp;ContainerMetadata{Name:hello-python5,Attempt:0,} returns container id \\\"59ff7a8553651222ed6f3e8a13801c2ae850f995d133fa5e79bb37da5b297db9\\\"\"\n\nkubectl get services<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Gives us:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>NAME                         TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)          AGE\n\nhello-python5-service        LoadBalancer   10.152.183.154   192.168.1.23   8080:32278\/TCP   23s<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">There it is running at<a rel=\"noreferrer noopener\" href=\"http:\/\/www.google.com\/url?q=http%3A%2F%2F192.168.1.23%3A8080&amp;sa=D&amp;sntz=1&amp;usg=AFQjCNEd8zd92oymECZP4pYoUYrWs_-BKQ\" target=\"_blank\"> http:\/\/192.168.1.23:8080<\/a>, so let\u2019s give it a connect in a browser:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/www.geekmungus.co.uk\/wp-content\/uploads\/2021\/08\/image-2.png\" alt=\"\" class=\"wp-image-774\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">And you can see we really are running the expected image, because its the hello-python5 one as we wanted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Using an External Public Registry (e.g. DockerHub)<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/microk8s.io\/docs\/registry-public\">https:\/\/microk8s.io\/docs\/registry-public<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create an account at Docker Hub.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You\u2019ll also need to create a repository. On your master node run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Docker login<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Enter your logon details.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now lets create a new image and push it up into the Docker Hub.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First make a copy of the existing application image definition.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cp -r hello-python5 hello-python6\n\ncd hello-python6\/app<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Make a change to the image\u2019s main.py, so you know its something different for when you run it. Build the image locally, then we\u2019ll push it up.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker build . -t geekmungus\/private:hello-python6<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Where \u201cgeekmungus\u201d is my DockerHub username, \u201cprivate\u201d is the repository name and \u201chello-python6\u201d is the tag (in this case the name of the application).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@k8s-master:\/home\/ubuntu\/application\/hello-python6\/app# docker images\n\nREPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE\n\ngeekmungus\/private              hello-python6       1dfc3b05a3ca        5 seconds ago       874MB<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Okay now we can push that repository up.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker push geekmungus\/private<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Cool, and there it is:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/5B5jdomctwr1PYSjybIOmcP4DfdkWQUMAiqRNi5Pok4pZtqIII8iYyX0JHwTdOgxt43i3A\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s delete the local copy to ensure we only ever use the pulled version, when we now do a deployment.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker images\n\nroot@k8s-master:\/home\/ubuntu\/application\/hello-python6\/app# docker images\n\nREPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE\n\ngeekmungus\/private              hello-python6       1dfc3b05a3ca        4 minutes ago       874MB\n\ndocker image rm 1dfc3b05a3ca <\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So now that image has gone and is not available locally, so it should pull from DockerHub now when we refer to it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Change the deployment.yaml and service.yaml in the hello-python6\/app folder, so everywhere where it did say \u201chello-python5\u201d it now says \u201chello-python6\u201d.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then ensure you put the image name in as: <em>geekmungus\/private:hello-python6<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f deployment.yaml\n\nkubectl apply -f service.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Watching the logs I got this error:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Aug  2 20:59:45 k8s-worker-01 microk8s.daemon-containerd&#91;1303]: time=\"2020-08-02T20:59:45.554847607+01:00\" level=info msg=\"PullImage \\\"geekmungus\/private:hello-python6\\\"\"\n\nAug  2 20:59:47 k8s-worker-01 microk8s.daemon-containerd&#91;1303]: time=\"2020-08-02T20:59:47.366927939+01:00\" level=error msg=\"PullImage \\\"geekmungus\/private:hello-python6\\\" failed\" error=\"failed to pull and unpack image \\\"docker.io\/geekmungus\/private:hello-python6\\\": failed to resolve reference \\\"docker.io\/geekmungus\/private:hello-python \\\": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/stackoverflow.com\/questions\/56642311\/microk8s-cannot-pull-from-private-registry\">https:\/\/stackoverflow.com\/questions\/56642311\/microk8s-cannot-pull-from-private-registry<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/ubuntu\/microk8s\/issues\/512\">https:\/\/github.com\/ubuntu\/microk8s\/issues\/512<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So run this to create a secret to be used when you connect to the external public repository.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl create secret docker-registry regcred --docker-username=&lt;yourdockerhubusername> --docker-password=&lt;password> --docker-email=&lt;youremailaddress><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And then we see:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@k8s-master:\/home\/ubuntu\/application\/hello-python6\/app# kubectl create secret docker-registry regcred --docker-username=&lt;yourdockerhubusername> --docker-password=&lt;password> --docker-email=&lt;youremailaddress> --docker-server=https:\/\/index.docker.io\/v1\/\n\nsecret\/regcred created<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We now have a secret called &#8220;regcred&#8221; we can use in our deployments.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now within the deployment.yaml, you need to refer to it so your deployment.yaml will end up looking like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1\n\nkind: Deployment\n\nmetadata:\n\n  name: hello-python6\n\nspec:\n\n  selector:\n\n    matchLabels:\n\n      app: hello-python6\n\n  replicas: 1\n\n  template:\n\n    metadata:\n\n      labels:\n\n        app: hello-python6\n\n    spec:\n\n      containers:\n\n      - name: hello-python6\n\n        image: geekmungus\/private:hello-python6\n\n        ports:\n\n        - containerPort: 5000\n\n      imagePullSecrets:\n\n      - name: regcred<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now redeploy with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Kubectl apply -f deployment.yaml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It might take a little while because it will be downloading the image from dockerhub, but then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@k8s-master:\/home\/ubuntu\/application\/hello-python6\/app# kubectl get pods -o wide\n\nNAME                                  READY   STATUS              RESTARTS   AGE     IP           NODE            NOMINATED NODE   READINESS GATES\n\nhello-python6-7ccb5c4bf5-4z9sf        0\/1     ContainerCreating   0          8s      &lt;none>       k8s-worker-01   &lt;none>           &lt;none>\n\nroot@k8s-master:\/home\/ubuntu\/application\/hello-python6\/app# kubectl get pods -o wide\n\nNAME                                  READY   STATUS    RESTARTS   AGE     IP           NODE            NOMINATED NODE   READINESS GATES\n\nhello-python6-7ccb5c4bf5-4z9sf        1\/1     Running   0          67s     10.1.81.11   k8s-worker-01   &lt;none>           &lt;none><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Finally deploy the service:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl apply -f service.yaml\n\nroot@k8s-master:\/home\/ubuntu\/application\/hello-python6\/app# kubectl get services\n\nNAME                         TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)          AGE\n\nhello-python6-service        LoadBalancer   10.152.183.229   192.168.1.24   8080:32475\/TCP   6s\n\nkubernetes                   ClusterIP      10.152.183.1     &lt;none>         443\/TCP          46h<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/mcsiKBme77lkSDPV46uMQTX0hLhjPl5eb2VSiArohV8WoHoCEAJIlBh6Kw0rdDomjBjS0Q\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">And we are done! We can see the application running on that port in our browser and it is the image we expected to see.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/microk8s.io\/docs\/registry-images So images. A container is based on an image. You can pull these images in from the outside world, e.g. from a Public, Private registry, or from the built-in registry. For this copy the &#8220;hello-python&#8221; directory we created in Part 2 into one called &#8220;hello-python3&#8221;, you can delete the .tar file in there for &#8230; <a title=\"MicroK8s (Kubernetes) &#8211; Raspberry Pi Ubuntu Linux Basic Setup Guide &#8211; Part 4 (Image Repositories)\" class=\"read-more\" href=\"https:\/\/geekmungus.co.uk\/?p=771\" aria-label=\"Read more about MicroK8s (Kubernetes) &#8211; Raspberry Pi Ubuntu Linux Basic Setup Guide &#8211; Part 4 (Image Repositories)\">Read more<\/a><\/p>\n","protected":false},"author":4,"featured_media":763,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,11],"tags":[],"class_list":["post-771","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-kubernetes","category-linux"],"_links":{"self":[{"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/771","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=771"}],"version-history":[{"count":1,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/771\/revisions"}],"predecessor-version":[{"id":1377,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/771\/revisions\/1377"}],"wp:attachment":[{"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/geekmungus.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}