64
bewerkingen
k (Minnozz heeft pagina HSNWiki:Kubernetes hernoemd naar Projects:Kubernetes over een doorverwijzing) |
|||
(13 tussenliggende versies door 3 gebruikers niet weergegeven) | |||
Regel 949: | Regel 949: | ||
To begin with, the registry will need storage for its images. True to our earlier experiments, we start by creating a persistent volume claim. (I'll assume there's a persistent volume to fulfill it; if not, check above how to create one yourself.) | To begin with, the registry will need storage for its images. True to our earlier experiments, we start by creating a persistent volume claim. (I'll assume there's a persistent volume to fulfill it; if not, check above how to create one yourself.) | ||
<pre> | |||
apiVersion: v1 | |||
kind: PersistentVolumeClaim | |||
metadata: | |||
name: registry-files | |||
spec: | |||
storageClassName: default | |||
accessModes: | |||
- ReadWriteOnce | |||
resources: | |||
requests: | |||
storage: 20Gi | |||
</pre> | |||
The registry deployment: | |||
To | <pre> | ||
apiVersion: apps/v1 | |||
kind: Deployment | |||
metadata: | |||
name: registry | |||
spec: | |||
selector: | |||
matchLabels: | |||
app: registry | |||
replicas: 1 | |||
template: | |||
metadata: | |||
labels: | |||
app: registry | |||
spec: | |||
volumes: | |||
- name: registrystorage | |||
persistentVolumeClaim: | |||
claimName: registry-files | |||
containers: | |||
- name: registry | |||
image: registry:2 | |||
ports: | |||
- containerPort: 5000 | |||
volumeMounts: | |||
- mountPath: /var/lib/registry | |||
name: registrystorage | |||
</pre> | |||
And a Service + Ingress to make it accessible on a new hostname. I found that Docker doesn't support accessing a registry with a path prefix, so we have to give it its own hostname. Luckily, with Traefik, it's easy to route; you'll only have to add a record in DNS. | |||
<pre> | |||
apiVersion: v1 | |||
kind: Service | |||
metadata: | |||
name: registry-service | |||
spec: | |||
selector: | |||
app: registry | |||
ports: | |||
- name: registry | |||
port: 5000 | |||
protocol: TCP | |||
--- | |||
apiVersion: extensions/v1beta1 | |||
kind: Ingress | |||
metadata: | |||
name: registry-ingress | |||
spec: | |||
rules: | |||
- host: kuberegistry.sjorsgielen.nl | |||
http: | |||
paths: | |||
- path: / | |||
backend: | |||
serviceName: registry-service | |||
servicePort: 5000 | |||
</pre> | |||
After a minute, as before, https://kuberegistry.sjorsgielen.nl/v2/ (replace with your own hostname) should return 200 OK with a page content of "{}". | |||
To test whether it's working, let's take the Ubuntu Docker image and push it onto our registry, as per [https://docs.docker.com/registry/ more or less these instructions]. Here, it's important that the registry is well-reachable over HTTPS, as Docker will only allow non-SSL HTTP communication over localhost! (Although you could get around this with a <code>kubectl port-forward</code>.) | |||
<pre> | |||
$ docker pull ubuntu | |||
$ docker image tag ubuntu kuberegistry.sjorsgielen.nl/myubuntu | |||
$ docker push kuberegistry.sjorsgielen.nl/myubuntu | |||
[...] Retrying in 10 seconds | |||
</pre> | |||
That seems to fail. As before, we can figure out the root cause by getting the logs of the Registry pod: | |||
<pre> | |||
$ kubectl logs registry-6bf4dbcfb-9csf5 | |||
[...] | |||
time="2019-03-28T21:44:04.465658668Z" level=error msg="response completed with error" err.code=unknown err.detail="filesystem: mkdir /var/lib/registry/docker: permission denied" err.message="unknown error" go.version=go1.11.2 http.request.host=kuberegistry.sjorsgielen.nl http.request.id=c00f2785-30b0-469d-bcff-70a12c0f604b http.request.method=POST http.request.remoteaddr=10.107.160.0 http.request.uri="/v2/myubuntu/blobs/uploads/" http.request.useragent="docker/18.06.1-ce go/go1.10.4 git-commit/e68fc7a kernel/4.4.0-112-generic os/linux arch/amd64 UpstreamClient(Docker-Client/18.06.1-ce \(linux\))" http.response.contenttype="application/json; charset=utf-8" http.response.duration=125.482304ms http.response.status=500 http.response.written=164 vars.name=myubuntu | |||
</pre> | |||
A "permission denied" error in "mkdir /var/lib/registry/docker". Now, we may not know the PersistentVolume behind whatever is mounted in the registry, but we can quickly find out by checking <code>kubectl describe deployment registry</code>, <code>kubectl get pvc</code> and <code>kubectl describe pv registry-storage</code>. In my case, it's because root squashing is enabled on my NFS mount and the directory is being accessed by root, therefore by an anonymous uid/gid, which doesn't have rights in the directory. It's easily fixed and now the push works: | |||
<pre> | |||
$ docker push kuberegistry.sjorsgielen.nl/myubuntu | |||
The push refers to repository [kuberegistry.sjorsgielen.nl/myubuntu] | |||
b57c79f4a9f3: Pushed | |||
d60e01b37e74: Pushed | |||
e45cfbc98a50: Pushed | |||
762d8e1a6054: Pushed | |||
latest: digest: sha256:f2557f94cac1cc4509d0483cb6e302da841ecd6f82eb2e91dc7ba6cfd0c580ab size: 1150 | |||
</pre> | |||
Now, let's make our own Docker image, push it, and start it in a Pod! | |||
Here's an example Dockerfile that runs a tiny Perl-based webserver that always responds with its own hostname: | |||
<pre> | |||
$ cat Dockerfile | |||
FROM ubuntu:bionic | |||
RUN apt-get update \ | |||
&& apt-get install -y libmojolicious-perl \ | |||
&& rm -rf /var/lib/apt/lists/* | |||
# Normally, you'd use COPY here, but I wanted to keep this in one file | |||
RUN echo "#!/usr/bin/env perl" >>/app.pl \ | |||
&& echo "use Mojolicious::Lite;" >>/app.pl \ | |||
&& echo "get '/' => sub {" >>/app.pl \ | |||
&& echo " shift->render(text => 'Hello World!'); " >>/app.pl \ | |||
&& echo "};" >>/app.pl \ | |||
&& echo "app->start;" >>/app.pl \ | |||
&& chmod +x /app.pl | |||
EXPOSE 3000 | |||
CMD ["/app.pl", "daemon", "-l"] | |||
$ docker build -t kuberegistry.sjorsgielen.nl/helloworld:latest . | |||
$ docker push kuberegistry.sjorsgielen.nl/helloworld:latest | |||
</pre> | |||
At this point, you should be able to write a Deployment, Service and Ingress for this application, using the examples above. <code>kubectl apply</code> should then start the Pod, Traefik should route the service and whatever host/path you configured should quickly be reachable and respond with "Hello World". We've created our own image and ran it on your cluster! | |||
= To do = | = To do = | ||
Regel 958: | Regel 1.089: | ||
* Kubernetes Dashboard | * Kubernetes Dashboard | ||
* Attempt Kubernetes upgrade from 1.13 to 1.14 | * Attempt Kubernetes upgrade from 1.13 to 1.14 | ||
** https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-14/ | |||
** First, do a normal apt upgrade (the kubernetes packages are held and will not be modified) | |||
** Then, unhold the kubeadm package on the master, upgrade it to the right version, then re-hold it | |||
*** This only worked for me after unholding the kubelet and upgrading it as well. | |||
** On the master, "kubeadm upgrade plan", then "kubeadm upgrade apply v1.14.x" | |||
** Upgrade CNI controller by re-running the same <code>kubectl apply</code> as earlier | |||
** Unhold the kubelet and kubectl packages on the master, upgrade them and re-hold them, then restart the kubelet | |||
** For each worker, unhold the kubeadm package, upgrade it, rehold it; cordon (drain) the node; upgrade the node config; install the new kubelet version and restart it; uncordon the node. | |||
*** Here too, this only worked for me after unholding the kubelet and upgrading it as well. | |||
* Try getting information on a pod from inside it using the Kubernetes API | * Try getting information on a pod from inside it using the Kubernetes API | ||
** https://kubernetes.io/docs/tasks/administer-cluster/access-cluster-api/#accessing-the-api-from-a-pod | |||
** <code>wget --ca-certificate=/run/secrets/kubernetes.io/serviceaccount/ca.crt -qO- https://kubernetes.default.svc.cluster.local/api/</code> | |||
** Doesn't need using the Kubernetes API, can be done using env vars: https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/ | |||
* Play with native cronjobs | * Play with native cronjobs | ||
* Play with Statefulset / Daemonset | * Play with Statefulset / Daemonset | ||
Regel 966: | Regel 1.109: | ||
** Allow K8s API communication from a pod, but only to receive information about itself | ** Allow K8s API communication from a pod, but only to receive information about itself | ||
** Basically: Make it impossible to root a node even with "broad" privileges on the Kubernetes API server | ** Basically: Make it impossible to root a node even with "broad" privileges on the Kubernetes API server | ||
** https://kubernetes.io/docs/concepts/policy/pod-security-policy/ | |||
* Limiting pods in memory, CPU, I/O | * Limiting pods in memory, CPU, I/O | ||
* Limiting pods in network communication | * Limiting pods in network communication | ||
[[Categorie:Projects]] |