mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-08-19 03:56:24 +00:00
Modularize the self-hosted registry section and remove it by default
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
## Using images from the Docker Hub
|
||||
|
||||
- For everyone's convenience, we took care of building DockerCoins images
|
||||
|
||||
- We pushed these images to the DockerHub, under the [dockercoins](https://hub.docker.com/u/dockercoins) user
|
||||
|
||||
- These images are *tagged* with a version number, `v0.1`
|
||||
|
||||
- The full image names are therefore:
|
||||
|
||||
- `dockercoins/hasher:v0.1`
|
||||
|
||||
- `dockercoins/rng:v0.1`
|
||||
|
||||
- `dockercoins/webui:v0.1`
|
||||
|
||||
- `dockercoins/worker:v0.1`
|
||||
|
||||
---
|
||||
|
||||
## Setting `$REGISTRY` and `$TAG`
|
||||
|
||||
- In the upcoming exercises and labs, we use a couple of environment variables:
|
||||
|
||||
- `$REGISTRY` as a prefix to all image names
|
||||
|
||||
- `$TAG` as the image version tag
|
||||
|
||||
- For example, the worker image is `$REGISTRY/worker:$TAG`
|
||||
|
||||
- If you copy-paste the commands in these exercises:
|
||||
|
||||
**make sure that you set `$REGISTRY` and `$TAG` first!**
|
||||
|
||||
- For example:
|
||||
```
|
||||
export REGISTRY=dockercoins TAG=v0.1
|
||||
```
|
||||
|
||||
(this will expand `$REGISTRY/worker:$TAG` to `dockercoins/worker:v0.1`)
|
||||
@@ -0,0 +1,235 @@
|
||||
## Self-hosting our registry
|
||||
|
||||
*Note: this section shows how to run the Docker
|
||||
open source registry and use it to ship images
|
||||
on our cluster. While this method works fine,
|
||||
we recommend that you consider using one of the
|
||||
hosted, free automated build services instead.
|
||||
It will be much easier!*
|
||||
|
||||
*If you need to run a registry on premises,
|
||||
this section gives you a starting point, but
|
||||
you will need to make a lot of changes so that
|
||||
the registry is secured, highly available, and
|
||||
so that your build pipeline is automated.*
|
||||
|
||||
---
|
||||
|
||||
## Using the open source registry
|
||||
|
||||
- We need to run a `registry` container
|
||||
|
||||
- It will store images and layers to the local filesystem
|
||||
<br/>(but you can add a config file to use S3, Swift, etc.)
|
||||
|
||||
- Docker *requires* TLS when communicating with the registry
|
||||
|
||||
- unless for registries on `127.0.0.0/8` (i.e. `localhost`)
|
||||
|
||||
- or with the Engine flag `--insecure-registry`
|
||||
|
||||
- Our strategy: publish the registry container on a NodePort,
|
||||
<br/>so that it's available through `127.0.0.1:xxxxx` on each node
|
||||
|
||||
---
|
||||
|
||||
## Deploying a self-hosted registry
|
||||
|
||||
- We will deploy a registry container, and expose it with a NodePort
|
||||
|
||||
.exercise[
|
||||
|
||||
- Create the registry service:
|
||||
```bash
|
||||
kubectl create deployment registry --image=registry
|
||||
```
|
||||
|
||||
- Expose it on a NodePort:
|
||||
```bash
|
||||
kubectl expose deploy/registry --port=5000 --type=NodePort
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Connecting to our registry
|
||||
|
||||
- We need to find out which port has been allocated
|
||||
|
||||
.exercise[
|
||||
|
||||
- View the service details:
|
||||
```bash
|
||||
kubectl describe svc/registry
|
||||
```
|
||||
|
||||
- Get the port number programmatically:
|
||||
```bash
|
||||
NODEPORT=$(kubectl get svc/registry -o json | jq .spec.ports[0].nodePort)
|
||||
REGISTRY=127.0.0.1:$NODEPORT
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Testing our registry
|
||||
|
||||
- A convenient Docker registry API route to remember is `/v2/_catalog`
|
||||
|
||||
.exercise[
|
||||
|
||||
<!-- ```hide kubectl wait deploy/registry --for condition=available```-->
|
||||
|
||||
- View the repositories currently held in our registry:
|
||||
```bash
|
||||
curl $REGISTRY/v2/_catalog
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
--
|
||||
|
||||
We should see:
|
||||
```json
|
||||
{"repositories":[]}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing our local registry
|
||||
|
||||
- We can retag a small image, and push it to the registry
|
||||
|
||||
.exercise[
|
||||
|
||||
- Make sure we have the busybox image, and retag it:
|
||||
```bash
|
||||
docker pull busybox
|
||||
docker tag busybox $REGISTRY/busybox
|
||||
```
|
||||
|
||||
- Push it:
|
||||
```bash
|
||||
docker push $REGISTRY/busybox
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Checking again what's on our local registry
|
||||
|
||||
- Let's use the same endpoint as before
|
||||
|
||||
.exercise[
|
||||
|
||||
- Ensure that our busybox image is now in the local registry:
|
||||
```bash
|
||||
curl $REGISTRY/v2/_catalog
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
The curl command should now output:
|
||||
```json
|
||||
{"repositories":["busybox"]}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Building and pushing our images
|
||||
|
||||
- We are going to use a convenient feature of Docker Compose
|
||||
|
||||
.exercise[
|
||||
|
||||
- Go to the `stacks` directory:
|
||||
```bash
|
||||
cd ~/container.training/stacks
|
||||
```
|
||||
|
||||
- Build and push the images:
|
||||
```bash
|
||||
export REGISTRY
|
||||
export TAG=v0.1
|
||||
docker-compose -f dockercoins.yml build
|
||||
docker-compose -f dockercoins.yml push
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
Let's have a look at the `dockercoins.yml` file while this is building and pushing.
|
||||
|
||||
---
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
rng:
|
||||
build: dockercoins/rng
|
||||
image: ${REGISTRY-127.0.0.1:5000}/rng:${TAG-latest}
|
||||
deploy:
|
||||
mode: global
|
||||
...
|
||||
redis:
|
||||
image: redis
|
||||
...
|
||||
worker:
|
||||
build: dockercoins/worker
|
||||
image: ${REGISTRY-127.0.0.1:5000}/worker:${TAG-latest}
|
||||
...
|
||||
deploy:
|
||||
replicas: 10
|
||||
```
|
||||
|
||||
.warning[Just in case you were wondering ... Docker "services" are not Kubernetes "services".]
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Avoiding the `latest` tag
|
||||
|
||||
.warning[Make sure that you've set the `TAG` variable properly!]
|
||||
|
||||
- If you don't, the tag will default to `latest`
|
||||
|
||||
- The problem with `latest`: nobody knows what it points to!
|
||||
|
||||
- the latest commit in the repo?
|
||||
|
||||
- the latest commit in some branch? (Which one?)
|
||||
|
||||
- the latest tag?
|
||||
|
||||
- some random version pushed by a random team member?
|
||||
|
||||
- If you keep pushing the `latest` tag, how do you roll back?
|
||||
|
||||
- Image tags should be meaningful, i.e. correspond to code branches, tags, or hashes
|
||||
|
||||
---
|
||||
|
||||
## Checking the content of the registry
|
||||
|
||||
- All our images should now be in the registry
|
||||
|
||||
.exercise[
|
||||
|
||||
- Re-run the same `curl` command as earlier:
|
||||
```bash
|
||||
curl $REGISTRY/v2/_catalog
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
*In these slides, all the commands to deploy
|
||||
DockerCoins will use a $REGISTRY environment
|
||||
variable, so that we can quickly switch from
|
||||
the self-hosted registry to pre-built images
|
||||
hosted on the Docker Hub. So make sure that
|
||||
this $REGISTRY variable is set correctly when
|
||||
running the exercises!*
|
||||
@@ -1,328 +1,3 @@
|
||||
# Shipping images with a registry
|
||||
|
||||
- Initially, our app was running on a single node
|
||||
|
||||
- We could *build* and *run* in the same place
|
||||
|
||||
- Therefore, we did not need to *ship* anything
|
||||
|
||||
- Now that we want to run on a cluster, things are different
|
||||
|
||||
- The easiest way to ship container images is to use a registry
|
||||
|
||||
---
|
||||
|
||||
## How Docker registries work (a reminder)
|
||||
|
||||
- What happens when we execute `docker run alpine` ?
|
||||
|
||||
- If the Engine needs to pull the `alpine` image, it expands it into `library/alpine`
|
||||
|
||||
- `library/alpine` is expanded into `index.docker.io/library/alpine`
|
||||
|
||||
- The Engine communicates with `index.docker.io` to retrieve `library/alpine:latest`
|
||||
|
||||
- To use something else than `index.docker.io`, we specify it in the image name
|
||||
|
||||
- Examples:
|
||||
```bash
|
||||
docker pull gcr.io/google-containers/alpine-with-bash:1.0
|
||||
|
||||
docker build -t registry.mycompany.io:5000/myimage:awesome .
|
||||
docker push registry.mycompany.io:5000/myimage:awesome
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The plan
|
||||
|
||||
We are going to:
|
||||
|
||||
- **build** images for our app,
|
||||
|
||||
- **ship** these images with a registry,
|
||||
|
||||
- **run** deployments using these images,
|
||||
|
||||
- expose (with a ClusterIP) the deployments that need to communicate together,
|
||||
|
||||
- expose (with a NodePort) the web UI so we can access it from outside.
|
||||
|
||||
---
|
||||
|
||||
## Building and shipping our app
|
||||
|
||||
- We will pick a registry
|
||||
|
||||
(let's pretend the address will be `REGISTRY:PORT`)
|
||||
|
||||
- We will build on our control node (`node1`)
|
||||
|
||||
(the images will be named `REGISTRY:PORT/servicename`)
|
||||
|
||||
- We will push the images to the registry
|
||||
|
||||
- These images will be usable by the other nodes of the cluster
|
||||
|
||||
(i.e., we could do `docker run REGISTRY:PORT/servicename` from these nodes)
|
||||
|
||||
---
|
||||
|
||||
## A shortcut opportunity
|
||||
|
||||
- As it happens, the images that we need do already exist on the Docker Hub:
|
||||
|
||||
https://hub.docker.com/r/dockercoins/
|
||||
|
||||
- We could use them instead of using our own registry and images
|
||||
|
||||
*In the following slides, we are going to show how to run a registry
|
||||
and use it to host container images. We will also show you how to
|
||||
use the existing images from the Docker Hub, so that you can catch
|
||||
up (or skip altogether the build/push part) if needed.*
|
||||
|
||||
---
|
||||
|
||||
## Which registry do we want to use?
|
||||
|
||||
- We could use the Docker Hub
|
||||
|
||||
- There are alternatives like Quay
|
||||
|
||||
- Each major cloud provider has an option as well
|
||||
|
||||
(ACR on Azure, ECR on AWS, GCR on Google Cloud...)
|
||||
|
||||
- There are also commercial products to run our own registry
|
||||
|
||||
(Docker EE, Quay...)
|
||||
|
||||
- And open source options, too!
|
||||
|
||||
*We are going to self-host an open source registry because it's the most generic solution for this workshop. We will use Docker's reference
|
||||
implementation for simplicity.*
|
||||
|
||||
---
|
||||
|
||||
## Using the open source registry
|
||||
|
||||
- We need to run a `registry` container
|
||||
|
||||
- It will store images and layers to the local filesystem
|
||||
<br/>(but you can add a config file to use S3, Swift, etc.)
|
||||
|
||||
- Docker *requires* TLS when communicating with the registry
|
||||
|
||||
- unless for registries on `127.0.0.0/8` (i.e. `localhost`)
|
||||
|
||||
- or with the Engine flag `--insecure-registry`
|
||||
|
||||
- Our strategy: publish the registry container on a NodePort,
|
||||
<br/>so that it's available through `127.0.0.1:xxxxx` on each node
|
||||
|
||||
---
|
||||
|
||||
## Deploying a self-hosted registry
|
||||
|
||||
- We will deploy a registry container, and expose it with a NodePort
|
||||
|
||||
.exercise[
|
||||
|
||||
- Create the registry service:
|
||||
```bash
|
||||
kubectl create deployment registry --image=registry
|
||||
```
|
||||
|
||||
- Expose it on a NodePort:
|
||||
```bash
|
||||
kubectl expose deploy/registry --port=5000 --type=NodePort
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Connecting to our registry
|
||||
|
||||
- We need to find out which port has been allocated
|
||||
|
||||
.exercise[
|
||||
|
||||
- View the service details:
|
||||
```bash
|
||||
kubectl describe svc/registry
|
||||
```
|
||||
|
||||
- Get the port number programmatically:
|
||||
```bash
|
||||
NODEPORT=$(kubectl get svc/registry -o json | jq .spec.ports[0].nodePort)
|
||||
REGISTRY=127.0.0.1:$NODEPORT
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Testing our registry
|
||||
|
||||
- A convenient Docker registry API route to remember is `/v2/_catalog`
|
||||
|
||||
.exercise[
|
||||
|
||||
<!-- ```hide kubectl wait deploy/registry --for condition=available```-->
|
||||
|
||||
- View the repositories currently held in our registry:
|
||||
```bash
|
||||
curl $REGISTRY/v2/_catalog
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
--
|
||||
|
||||
We should see:
|
||||
```json
|
||||
{"repositories":[]}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing our local registry
|
||||
|
||||
- We can retag a small image, and push it to the registry
|
||||
|
||||
.exercise[
|
||||
|
||||
- Make sure we have the busybox image, and retag it:
|
||||
```bash
|
||||
docker pull busybox
|
||||
docker tag busybox $REGISTRY/busybox
|
||||
```
|
||||
|
||||
- Push it:
|
||||
```bash
|
||||
docker push $REGISTRY/busybox
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
|
||||
## Checking again what's on our local registry
|
||||
|
||||
- Let's use the same endpoint as before
|
||||
|
||||
.exercise[
|
||||
|
||||
- Ensure that our busybox image is now in the local registry:
|
||||
```bash
|
||||
curl $REGISTRY/v2/_catalog
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
The curl command should now output:
|
||||
```json
|
||||
{"repositories":["busybox"]}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Building and pushing our images
|
||||
|
||||
- We are going to use a convenient feature of Docker Compose
|
||||
|
||||
.exercise[
|
||||
|
||||
- Go to the `stacks` directory:
|
||||
```bash
|
||||
cd ~/container.training/stacks
|
||||
```
|
||||
|
||||
- Build and push the images:
|
||||
```bash
|
||||
export REGISTRY
|
||||
export TAG=v0.1
|
||||
docker-compose -f dockercoins.yml build
|
||||
docker-compose -f dockercoins.yml push
|
||||
```
|
||||
|
||||
]
|
||||
|
||||
Let's have a look at the `dockercoins.yml` file while this is building and pushing.
|
||||
|
||||
---
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
rng:
|
||||
build: dockercoins/rng
|
||||
image: ${REGISTRY-127.0.0.1:5000}/rng:${TAG-latest}
|
||||
deploy:
|
||||
mode: global
|
||||
...
|
||||
redis:
|
||||
image: redis
|
||||
...
|
||||
worker:
|
||||
build: dockercoins/worker
|
||||
image: ${REGISTRY-127.0.0.1:5000}/worker:${TAG-latest}
|
||||
...
|
||||
deploy:
|
||||
replicas: 10
|
||||
```
|
||||
|
||||
.warning[Just in case you were wondering ... Docker "services" are not Kubernetes "services".]
|
||||
|
||||
---
|
||||
|
||||
class: extra-details
|
||||
|
||||
## Avoiding the `latest` tag
|
||||
|
||||
.warning[Make sure that you've set the `TAG` variable properly!]
|
||||
|
||||
- If you don't, the tag will default to `latest`
|
||||
|
||||
- The problem with `latest`: nobody knows what it points to!
|
||||
|
||||
- the latest commit in the repo?
|
||||
|
||||
- the latest commit in some branch? (Which one?)
|
||||
|
||||
- the latest tag?
|
||||
|
||||
- some random version pushed by a random team member?
|
||||
|
||||
- If you keep pushing the `latest` tag, how do you roll back?
|
||||
|
||||
- Image tags should be meaningful, i.e. correspond to code branches, tags, or hashes
|
||||
|
||||
---
|
||||
|
||||
## Catching up
|
||||
|
||||
- If you have problems deploying the registry ...
|
||||
|
||||
- Or building or pushing the images ...
|
||||
|
||||
- Don't worry: you can easily use pre-built images from the Docker Hub!
|
||||
|
||||
- The images are named `dockercoins/worker:v0.1`, `dockercoins/rng:v0.1`, etc.
|
||||
|
||||
- To use them, just set the `REGISTRY` environment variable to `dockercoins`:
|
||||
```bash
|
||||
export REGISTRY=dockercoins
|
||||
```
|
||||
|
||||
- Make sure to set the `TAG` to `v0.1`
|
||||
|
||||
(our repositories on the Docker Hub do not provide a `latest` tag)
|
||||
|
||||
---
|
||||
|
||||
# Running our application on Kubernetes
|
||||
|
||||
- We can now deploy our code (as well as a redis instance)
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# Shipping images with a registry
|
||||
|
||||
- Initially, our app was running on a single node
|
||||
|
||||
- We could *build* and *run* in the same place
|
||||
|
||||
- Therefore, we did not need to *ship* anything
|
||||
|
||||
- Now that we want to run on a cluster, things are different
|
||||
|
||||
- The easiest way to ship container images is to use a registry
|
||||
|
||||
---
|
||||
|
||||
## How Docker registries work (a reminder)
|
||||
|
||||
- What happens when we execute `docker run alpine` ?
|
||||
|
||||
- If the Engine needs to pull the `alpine` image, it expands it into `library/alpine`
|
||||
|
||||
- `library/alpine` is expanded into `index.docker.io/library/alpine`
|
||||
|
||||
- The Engine communicates with `index.docker.io` to retrieve `library/alpine:latest`
|
||||
|
||||
- To use something else than `index.docker.io`, we specify it in the image name
|
||||
|
||||
- Examples:
|
||||
```bash
|
||||
docker pull gcr.io/google-containers/alpine-with-bash:1.0
|
||||
|
||||
docker build -t registry.mycompany.io:5000/myimage:awesome .
|
||||
docker push registry.mycompany.io:5000/myimage:awesome
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running DockerCoins on Kubernetes
|
||||
|
||||
- Create one deployment for each component
|
||||
|
||||
(hasher, redis, rng, webui, worker)
|
||||
|
||||
- Expose deployments that need to accept connections
|
||||
|
||||
(hasher, redis, rng, webui)
|
||||
|
||||
- For redis, we can use the official redis image
|
||||
|
||||
- For the 4 others, we need to build images and push them to some registry
|
||||
|
||||
---
|
||||
|
||||
## Building and shipping images
|
||||
|
||||
- There are *many* options!
|
||||
|
||||
- Manually:
|
||||
|
||||
- build locally (with `docker build` or otherwise)
|
||||
|
||||
- push to the registry
|
||||
|
||||
- Automatically:
|
||||
|
||||
- build and test locally
|
||||
|
||||
- when ready, commit and push a code repository
|
||||
|
||||
- the code repository notifies an automated build system
|
||||
|
||||
- that system gets the code, builds it, pushes the image to the registry
|
||||
|
||||
---
|
||||
|
||||
## Which registry do we want to use?
|
||||
|
||||
- There are SAAS products like Docker Hub, Quay ...
|
||||
|
||||
- Each major cloud provider has an option as well
|
||||
|
||||
(ACR on Azure, ECR on AWS, GCR on Google Cloud...)
|
||||
|
||||
- There are also commercial products to run our own registry
|
||||
|
||||
(Docker EE, Quay...)
|
||||
|
||||
- And open source options, too!
|
||||
|
||||
- When picking a registry, pay attention to its build system
|
||||
|
||||
(when it has one)
|
||||
@@ -32,7 +32,10 @@ chapters:
|
||||
- k8s/setup-k8s.md
|
||||
- k8s/kubectlrun.md
|
||||
- k8s/kubectlexpose.md
|
||||
- - k8s/ourapponkube.md
|
||||
- - k8s/shippingimages.md
|
||||
# - k8s/buildshiprun-selfhosted.md
|
||||
- k8s/buildshiprun-dockerhub.md
|
||||
- k8s/ourapponkube.md
|
||||
# - k8s/kubectlproxy.md
|
||||
# - k8s/localkubeconfig.md
|
||||
# - k8s/accessinternal.md
|
||||
|
||||
@@ -35,6 +35,9 @@ chapters:
|
||||
- k8s/setup-k8s.md
|
||||
- - k8s/kubectlrun.md
|
||||
- k8s/kubectlexpose.md
|
||||
- k8s/shippingimages.md
|
||||
#- k8s/buildshiprun-selfhosted.md
|
||||
- k8s/buildshiprun-dockerhub.md
|
||||
- k8s/ourapponkube.md
|
||||
#- k8s/kubectlproxy.md
|
||||
#- k8s/localkubeconfig.md
|
||||
|
||||
@@ -32,7 +32,10 @@ chapters:
|
||||
- k8s/setup-k8s.md
|
||||
- k8s/kubectlrun.md
|
||||
- k8s/kubectlexpose.md
|
||||
- - k8s/ourapponkube.md
|
||||
- - k8s/shippingimages.md
|
||||
- k8s/buildshiprun-selfhosted.md
|
||||
- k8s/buildshiprun-dockerhub.md
|
||||
- k8s/ourapponkube.md
|
||||
- k8s/kubectlproxy.md
|
||||
- k8s/localkubeconfig.md
|
||||
- k8s/accessinternal.md
|
||||
|
||||
@@ -32,7 +32,10 @@ chapters:
|
||||
- k8s/setup-k8s.md
|
||||
- k8s/kubectlrun.md
|
||||
- k8s/kubectlexpose.md
|
||||
- - k8s/ourapponkube.md
|
||||
- - k8s/shippingimages.md
|
||||
#- k8s/buildshiprun-selfhosted.md
|
||||
- k8s/buildshiprun-dockerhub.md
|
||||
- k8s/ourapponkube.md
|
||||
- k8s/kubectlproxy.md
|
||||
- k8s/localkubeconfig.md
|
||||
- k8s/accessinternal.md
|
||||
|
||||
Reference in New Issue
Block a user