So you want to play with Kubernetes, try MiniKube

First off, if you have a few spare physical machines; or machines with enough resources to run a few well resourced VMs it is fairly simple to install Kubernetes itself. I have a fairly old OpenStack stack deployment yaml file that I still use to throw-up/tear-down multicompute node environments under OpenStack if I need something more powerful than MiniKube, but MiniKube is all you really need for development/testing on a regular basis.

However this post is on minikube. MiniKube is the best tool for testing out Kubernetes for a home lab if you are comfortable running everything on one machine if you have one powerful enough. Minikube provides a working environment including mutiple nodes (or course on the local machine) if required.

What is a powerful enough machine is a matter of debate; for example to test istio it is recomended to use 6 cpus and 8Gb of memory; I had no trouble with 2 cpus and a physical machine with only 6Gb of memory and only a wireless interface for downloads, running all examples and kiali (it was slow, bit everything worked).

As a general rule you should probably allocate as much resource as you can, especially as minikube can run multiple nodes if you wish to by simply passing a command line flag to the start command.

One important thing to note about this post. I run minikube on a machine running docker using the docker driver. I strongly recomend you do the same so you can use docker commands to manage images in the cluster as discussed in some of the tips and tricks later on.

This post is about a few of the tips and tricks I have picked up using it.

For things I am testing (or even keeping) I prefer to keep them in their individual versioned directories where possible; for that reason I skip the steps some installers want of copying things to /usr/local/bin as you would only do that if you wanted every user on your machine to use them plus do not want aliases in your global profile. One advantage is that you can easily have multiple versions and just update the aliases.

Installing MiniKube and additional components

We will start off with configuring it to be useful. Note that I install everything under a directory ~/installs/kubernetes; you can place it in any directory of you choice.

# --- I keep everything under one directory and use aliases to run them
INST_DIR="~/installs/kuberernetes"
mkdir -p ${INST_DIR}
# --- get minikube
mkdir -p ${INST_DIR}/kuberernetes/minikube
cd ${INST_DIR}/kuberernetes/minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
# --- get istio
mkdir -p ${INST_DIR}/kuberernetes/istio
cd ${INST_DIR}/kuberernetes/istio
#     check https://github.com/istio/istio/releases for the latest release available ---
#     I am using 1.10.1 which is the latest at the time I write this
wget https://github.com/istio/istio/releases/download/1.10.1/istio-1.10.1-linux-amd64.tar.gz
tar -zxvf istio-1.10.1-linux-amd64.tar.gz
/bin/rm istio-1.10.1-linux-amd64.tar.gz

For things I am testing (or even keeping) I prefer to keep them in their individual versioned directories where possible; for that reason I skip the steps some installers want of copying things to /usr/local/bin as you would only do that if you wanted every user on your machine to use them plus do not want aliases in your global profile.

I just refer to the commands by aliases. So add the below lines to your ~/,bashrc (if using bash) or the profile file of whatever shell you use. Note the alias entry for ‘kubectl’, most documentation will recomend you download the latest copy of kubectl but as minikube has its own copy built in which is at the correct version for minikube you should use that copy, an example is the last of the three aliases shown below allowing the command ‘kubectl’ to be used at te terminal so copy/paste from websites you are interested in will work.

alias minikube="/home/mark/installs/kubernetes/minikube/minikube-linux-amd64"
alias istioctl="/home/mark/installs/kubernetes/istio/istio-1.10.1/bin/istioctl"
alias kubectl='minikube kubectl --'

Right, we are ready to start things up. Remember to ‘source ~/.bashrc’ (or start a new shell)

cd ~
minikube start --cpus 6 --memory 8192

At this point just occasionally use the command ‘kubectl get pod -A’. Wait until all pods are running before continuing.

Then you want istio installed

istioctl install

At this point just occasionally use the command ‘kubectl get pod -A’. Wait until all pods are running before continuing.

Lets add some of the whizzy-bang tools you will want to play with to monitor/visualize what you deploy now

kubectl apply -f istio/istio-1.10.1/samples/addons/grafana.yaml
kubectl apply -f istio/istio-1.10.1/samples/addons/jaeger.yaml
kubectl apply -f istio/istio-1.10.1/samples/addons/kiali.yaml
kubectl apply -f istio/istio-1.10.1/samples/addons/prometheus.yaml

For istio to be injected into pods you must set a label on each namespace you want istio used in, for playing about you will probably use the ‘default’ namespace so enter

kubectl label namespace default istio-injection=enabled

At this point you will probably want to test some of your own deployments. One additional tool I would suggest is a very strict kubernetes yaml file checker. That can be installed into its own directory and aliased as were the other commands

mkdir -p ~/installs/kuberernetes/kube-score
cd ~/installs/kuberernetes/kube-score
# ---- check https://github.com/zegl/kube-score/releases for the latest release available ---
wget https://github.com/zegl/kube-score/releases/download/v1.11.0/kube-score_1.11.0_linux_amd64.tar.gz
tar -zxvf kube-score_1.11.0_linux_amd64.tar.gz
alias kube-score="/home/mark/installs/kubernetes/kube-score/kube-score"   # << and add to ~/.bashrc with the other aliases
# usage kube-score score xxxx.yaml

Loading images into MikiKube

Now, you may want to use a local docker registry for images; good luck with that !.

There probably is a way to tell minikube to lookup local dns, its internal dns is perfectly able to resolve the internet addresses needed to download the images it needs to run, but it ignores the local host /etc/hsosts file and dns settings by default. Even if it could be overridden most 'local' docker registries are insecure so could not be used easily anyway.

However this is where the benefits of running minikube on a machine running docker come into play.

MiniKube has a 'minikube load xxx.tar' command where you can load into the cluster images you can manually save from your local docker repository and copy across to the machine running minikube to load; as an example (same machine running docker and minikube using that docker as the driver).

[mark@hawk ~]$ docker image list
REPOSITORY                       TAG       IMAGE ID       CREATED        SIZE
gcr.io/k8s-minikube/kicbase      v0.0.23   9fce26cb202e   10 days ago    1.09GB
docker-local:5000/portainer-ce   latest    96a1c6cc3d15   4 months ago   209MB
portainer/portainer-ce           latest    96a1c6cc3d15   4 months ago   209MB
localhost/mvs38j                 latest    1df77f61cbed   6 months ago   787MB
[mark@hawk ~]$ docker image save localhost/mvs38j > mvs38j.tar      # <-- save from docker 
[mark@hawk ~]$ minikube image load mvs38j.tar                       # <-- load to minikube

Important: a image loaded with 'minikube load xxx.tar' will not be shown with a 'minikube image ls' command. It is available and will be used by your containers, the pod logs will show 'image already present on local machine' when the pod starts; it seems to be invisible in cache until then.

However if your machine runs docker you can easily switch it from managing the machines docker instance to the kubernetes docker instance with the simple command 'eval $(minikube docker-env)' which allows you to use normal docker commands directly against the image within the minikube cluster as shown below where I switch the environment.

[mark@hawk ~]$ docker image list                  # <--- local machine, not many
REPOSITORY                       TAG       IMAGE ID       CREATED        SIZE
gcr.io/k8s-minikube/kicbase      v0.0.23   9fce26cb202e   10 days ago    1.09GB
docker-local:5000/portainer-ce   latest    96a1c6cc3d15   4 months ago   209MB
portainer/portainer-ce           latest    96a1c6cc3d15   4 months ago   209MB
localhost/mvs38j                 latest    1df77f61cbed   6 months ago   787MB
[mark@hawk ~]$ 
[mark@hawk ~]$ eval $(minikube docker-env)        # <--- switch to minikube environment
[mark@hawk ~]$ docker image list                  # <--- and we see lots of images
REPOSITORY                                TAG        IMAGE ID       CREATED         SIZE
istio/proxyv2                             1.10.1     5c66e8ac89a7   2 weeks ago     282MB
istio/pilot                               1.10.1     07d6b563f74b   2 weeks ago     217MB
quay.io/kiali/kiali                       v1.34      1d3ab1649f0b   5 weeks ago     194MB
k8s.gcr.io/kube-proxy                     v1.20.7    ff54c88b8ecf   5 weeks ago     118MB
k8s.gcr.io/kube-apiserver                 v1.20.7    034671b24f0f   5 weeks ago     122MB
k8s.gcr.io/kube-controller-manager        v1.20.7    22d1a2072ec7   5 weeks ago     116MB
k8s.gcr.io/kube-scheduler                 v1.20.7    38f903b54010   5 weeks ago     47.3MB
gcr.io/k8s-minikube/storage-provisioner   v5         6e38f40d628d   2 months ago    31.5MB
grafana/grafana                           7.4.3      c9e576dccd68   3 months ago    198MB
jimmidyson/configmap-reload               v0.5.0     d771cc9785a1   4 months ago    9.99MB
prom/prometheus                           v2.24.0    53fd5ed1cd48   5 months ago    173MB
localhost/mvs38j                          latest     1df77f61cbed   6 months ago    787MB
kubernetesui/dashboard                    v2.1.0     9a07b5b4bfac   6 months ago    226MB
jaegertracing/all-in-one                  1.20       84b5c715abd0   8 months ago    45.7MB
k8s.gcr.io/etcd                           3.4.13-0   0369cf4303ff   9 months ago    253MB
k8s.gcr.io/coredns                        1.7.0      bfe3a36ebd25   12 months ago   45.2MB
kubernetesui/metrics-scraper              v1.0.4     86262685d9ab   14 months ago   36.9MB
k8s.gcr.io/pause                          3.2        80d28bedfe5d   16 months ago   683kB
[mark@hawk ~]$ 

You can use ordinary docker commands against images within the minikube kubernetes cluster at this point; for example 'docker image rm 83e6a8464b84' will remove the image; although you should probably use 'minikube image rm' and just use docker to check.

Important notes

Do not expect docker images you download from dockerhub to run under kubernetes without modification. There are design issues to take into consideration, personally all my containers get an environment variable passed to them to indicate which application startup login chain to take. You may be able to get them to run if you set the kubernetes parameters for the container runasuser/runasgroup to 0 (if kubernetes allows such a thing) but that's obviously not ideal.

So create your own containers, or stick to kubernetes repositories not dockerhub ones until you know how to customise them.

Cleaning it all up again

To remove everything again, another benefit of keeping everything under its own directory structure is how easy it is to remove.

  • 'minikube stop' - shuts everything down in a state it can be restarted. It can be restarted from this state without losing any of your work with another 'minikube start --cpus 6 --memory 8192'
  • 'minikube delete' - use only when stopped, will delete everything you have done from minikube, you must start again from scratch
  • rm -rf the directory you installed all the downloads into, plus 'rm -rf ~/.minikube' as a lot of stuff is stored under your home directory in that folder
Posted in Automation, Unix | Comments Off on So you want to play with Kubernetes, try MiniKube

Setting up a CI pipeline on Linux for your home lab

Setting up a continuous integration pipeline for your home lab may seem like overkill, but if you have the memory available it is simple to do and if you have an interest in these tools why not :-). And it is so simple to do you should.

I must warn in advance that this post was done in a bit of a hurry as I have other things to do; bills to pay. So while I have tried to cover everything needed I will have missed bits. One example would be on how to tweak it so podman users can use the solution, I don’t use podman unless absolutely necessary so is you are using podman tough.

Requirements: You can have a VM instance with docker, a local container registry, a running gitlab-ce server, and the jenkins CI pipeline all installed on a VM with as little as 2vcpus and 8Gb memory. However note that if you want to integrate with kubernetes you should place that elsewhere as you really need another 4Gb memory minimum added to use that (even for minikube if you want to use kubevirt).

For those that are familiar with git every project lives in its own directory, that will not change if you run a local git server. You can be a little cleaner in that projects you are managing by git that you are not actively working on can be ‘pushed’ to your local git server and the local work directories removed (you can always pull them back from your local git server when you want to work on them again). But the only reason you would need a local git server is if you wanted to play with CI and don’t like the idea of updating a public source repository with multiple changes a day.

On the container front you should if you build images use the standard docker registry2 to provide a local insecure registry. This allows you to build container images from known ‘tested’ base images stored locally. Using the images from dockerhub means you cannot guarantee the build done today matches the build you did yesterday as base images on dockerhub are updated frequently; you need a local static base image.

Now with everything available in containers these days it all should be simple. And with a bit of simple customisation it is.

This post is about how to simply setup a CI pipeline in a home lab on a single VM. This post will cover the basic steps for

  1. Installing docker
  2. Setting up a local insecure container registry
  3. Installing and configuring the gitlab-ce container
  4. Installing and configuring the Jenkins container

Update: 2021/07/17 One warning: using containers ties you to that version; for example the gitlab-ce container jumped a major version and I cannot uograde without losing all my work. So a lot of effort to do if you update a container image later.

You do not have to install them all on a single VM, the benefit of doing so is simply that like containers being able to be moved about at will if your entice pipeline environment is on a single VM you can also easily move that about… if you have enough memory, a single VM install should work well with a VM using 7Gb memory and 2vcpus (allow 8Gb memory for headroom); if you don’t have that amount of memory available on a single machine by all means run the containers anywhere, the steps are pretty much the same. This post covers installing on a single VM, as I do move it about :-).

As the entire environment can be setup in containers on a single VM there is minimal effort needed to get a full CI pipeline for a home lab. However it should be noted that additional VMs (or additional packages added to the docker host allowing it to be more than just a docker build host) may be required.

For example if you wanted a pipeline to build a container using docker you could use the VM running jenkins as a build node, but if you wanted a pipeline to compile C code you would either need to install all the compilers on the VM, or simply add a new Jenkins node to another VM that had all those tools and configure your jenkins pipeline to use that node for that step.

This post will not cover the details of creating complex pipelines, although a few examples will be provided.

A couple of references you will see a lot that you will need to change in any example command shown are hostname entries

  • docker-local – my dns entry for the docker registry host server running the registry container, change it to the servername or ipaddr of your VM
  • gitlab-local – my dns entry for the gitlab-ce host server running that container, it must be a different name to that used to refer to the server (discussed later) [for this post the ip of the VM]
  • gitlab-server – my dns entry for the VM host [for this post the ip of the VM]

For the purposes of this post as I am discussing installing on one VM the above two hostname references would point to the same ip address, but they provide two different functions and should have their own dns entries in case you want to split them up onto seperate hosts later.

1. Installing docker-ce

Installing docker onto each different type of OS is fully covered on the docker website itself, you can find the instructions simply with a google search on “install docker-ce ” for example “install docker-ce centos”, the main page with all supported OSs listed is at https://docs.docker.com/engine/install/.

As you could be running any OS I won’t cover the install here, other than to point out additional steps that will be needed.

One note for Fedora users, the issue with cgroups2 being enabled on fedora by default is no longer an issue; docker-ce will now install and run on fedora without any OS settings needing to be changed.

On the assumption you will be using your CI pipeline to build container images you will not need docker or podman installed on any development desktops, just git to push your development builds into your pipeline. However if you are building containers on desktop for testing note that you would need to un-install podman (if installed) and install docker on all your development machines; there is no easy way of allowing podman to use an insecure registry.

After installing docker-ce into your pipeline VM…

  • ensure there is a ‘docker’ group created in /etc/group; if not create one
  • add userids that will need to use docker to the docker group to avoid the need to use root to do anything with docker (and I can’t remember the commands, I just ‘vi /etc/group’ and add them, bad I know). The group entry will look something like “docker:x:979:root,mark,anotheruser,anotheruser”
  • To allow any desktop/server you have just installed docker on to use an insecure registry ‘vi /etc/docker/daemon.json’ (if it does not exist create it) and add entries such as the below example
    {
      "insecure-registries" : [ "docker-local:5000","localhost:5000" ]
    }
    {
        "dns": ["192.168.1.179", "192.168.1.1", "8.8.8.8"]
    }
    

    If you are not using a local DNS server for your home lab that can resolve the servername you should use the ip-address in the insecure-registries entry such as “192.169.1.170:5000” rather than a servername such as docker-local. The :5000 is the port your docker container regisytry will listen on. If you are using a local DNS server then ensure you add the dns entry witk your local dns server and router in the list first also as if not set here docker will only use 8.8.8.8 and never resolve any local server names

The reason this post covers installing docker and omits any mention of podman is simply because the configuration file mentioned above in /etc/docker is of course for docker only; podman will not use an insecure registry.

One additional note for docker. By default deleting images using ‘docker image rm xxxxx’ on a machine running docker is not going to return any space. You should occasionally use the command “docker system prune -a” which will delete everything not in use on the client (anything not currently being used by a container) when issueing that command… repeat everything not being used by a container, make sure images you may want to use again are pushed to your local registry if they are not in use by a container when you run this command.

One additional tool I would recomend you install if you use docker is “docker-squash”. Iy you build your own container this is invaluable as it can squash dozens of layers of an image down to just a few and easlily halve the size of a container image; also I would generally run this against images downloaded from dockerhub as well as it can easily decrease the size of most of them as well. This can be installed with “pip install docker-squash” (or pip3/pip2 rather than pip if pip does not not default to the desired python version you have installed). For those that develop with podman rather than docker you will be upset to learn I am not aware of any equivalent tool for podman, which may be why many images on dockerhub are so needlessly large.

2. Setting up a local insecure container registry

First, this is easy to do. Secondly this is a long section as it also covers in brief some maintenance of your local registry you need to know that is not obvious or even mentioned in many posts about using a local registry2 instance.

For a home lab all that is needed is an insecure registry, this avoids the need to manage certificates for the registry. It allows every development server (that you manage) on your local network full access to the registry using docker if you set the insecure-registries section on each docker client machine as mentioned in the previous section.

(If using ‘podman’ tough luck, you need to look at the documentation on setting up a secure registry with valid letsencrypt certs, podman may be useful for stand-alone development on an internet facing machine using public repositores but is a pain to use on an insecure registry (maybe setup a local CA and use stunnel ?, or using an apache proxy as discussed later on in this section if you have valid certs for your webserver may work).

While the term “insecure registry” is used remember that each docker client machine using the registry must be explicitly configured to allow the insecure-registries, any client not setup to do so wil get an error like ‘http response where https expected’ whenever they try to use the registry, so access is still limited to clients configured for it.

The default port for an insecure registry is 5000 so on the server you will be running your local container registry on open port 5000 in the firewall. Then simply run the command below which will pull down the registry container and run it; and thats it you have a working local container registry. Read a few details below before running the command however !.

# A non-secure registry for local use
# The container will use /home/docker/data for storage rather than the default
# of an internal docker persistent volume.
docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  -v /home/docker/data:/var/lib/registry \
  -e REGISTRY_STORAGE_DELETE_ENABLED="true" \
  registry:2

In the regsistry start command above you will notice I included a parameter permitting images to be deleted, if you do not include that parameter you will never be able to delete images and the space used will eventually become extrememly large. Even with the parameter set deleting images is a multi-step process, you can delete as many images as you want and find zero space is reclaimed as they are just marked as deleted until you run the registry garbage collector to actually reclaim the space.

On space usage, if you exec into the registry container and use ‘df -k’ to see filesystem sizes you will see it uses all the space available on the filesystem. That may be something you do not want. You can limit the maximum size of space used by containers by modifying the docker config in /etc/sysconfig/docker-storage to add the line “DOCKER_STORAGE_OPTIONS= – -storage-opt dm.basesize=20G” however note this affects all containers you will start. It also needs to be done before you first start docker or you will have to delete and recreate all your existing containers.

On space again, well data really. Remember that containers do not persist storage across container restarts, as such you will notice that the example run command above uses a bind mount to a local filesystem directory; as such the storage options parameter is completely ignored for that filesystem as it gets the hosts freespace size, so why do it you ask ?. The reason is that by using a bind mount to the hosts filesystem the data remains when the container is stopped, and on a container restart using the same bind mount all the data is available for the container again. You would not want to push lots of images to your local registry and have them disappear every time you stopped the container; it does tie the container to the host with the filesystem so suitable for standalone docker not a docker swarm. It also allows the data to be backed up by your normal backup procedures.

Once you have decided what customisation you want to make, you can use the run command to start the registry containter to provide your local container registry.

To use the registry simply tag the container images with your local registry ip-address of servername and port 5000, for example my servername is docker-local so in order to store an image in my local registry you would tag it as in the example below for the ‘alpine’ image

docker pull alpine:latest                       # retireve an image (or use one you built yourself)
docker image list                               # you need the image id rather than the name
docker tag &ltimageidstring&gt docker-local:5000/alpine:latest    # tag to your local repository
docker push docker-local:5000/alpine:latest     # push to your local repository
docker image rm alpine:latest                   # untag the dockerhub entry

In the docker run command you would use the image name of docker-local:5000/alpine:latest to use the local copy instead of the dockerhub copy. Why would you want to do this ?, the answer is that you can guarantee each container you run uses a ‘known’ copy/version of the container image and it not going to be accidentally refreshed by a newer copy from dockerhub; so you can be sure each rebuild of a container in your CI pipeline is from a known base (and you you should refresh occasionally to get any security fixes… and retest everything again in your pipeline before depoying anything :-)). Another benefit of course is re-pulling images as needed from your local repository is across your local network, you don’t chew up internet bandwidth you may be paying for.

Should you have wisely used the parameter to allow images to be deleted from the registry in order to delete images you need to use the API, as that can get complicated I would recomend using a tool such as “git clone https://github.com/byrnedo/docker-reg-tool.git” which can then manage the regsitry using the command “INSECURE_REGISTRY=true ./docker_reg_tool http://docker-local:5000 [actions]” as the easiest way of listing and deleting images.

While it is fairly simple to view the contents of the local registry simply using a web browser with

see whats in the catalog
    http://docker-local:5000/v2/_catalog
    http://docker-local:5000/v2/_catalog?n=200       # default is max 100 entries to display , can change it with ?n=nn
assume one of the entries returned was 'ircserver' to see all available tags in the catalog for that
   http://docker-local:5000/v2/ircserver/tags/list

however if you have a lot of entries you are processing in a script using something like curl to get the list be aware the response may contain a link to a next page of responses your script would have to handle as well.

Deleting gets tricky and using a tool such as the one I refered to above makes it easier than trying to so it via creating your own custom scripts to post http delete requests. To do it yourself you would need to inspect the image you wish to delete to obtain the digest (ie: docker inspect my.docker.registry.com:5000/ubuntu:latest would in the response somewhere return something like RepoDigests”: [“docker-local:5000/ubuntu@sha256:74a1b5f5c5d771cf3570fa0f050e0c827538b7fe1873bc88b85d56818df3f2bc”]) and issue the delete with using that information (ie: curl -vk -X DELETE https://docker-local:5000/v2/mytestdockerrepo/manifests/sha256:66675d81b9bd5eafc105832b78abb91cab975bbcf028ca4bce4afe73f66914ee)… basically it is much easier to use an existing tool like the one mentioned earlier.

As I mentioned earlier issuing delete requests for images in your registry will not actually reclaim any space. In order to actually reclaim space used by the deleted images you need to exec into the registry2 container and run the garbage collector

docker exec -ti registry2 /bin/bash    # replace registry2 with what you named your register container
bin/registry garbage-collect [--dry-run] /etc/docker/registry/config.yml
exit

There may on occasion be a need for you to allow external users to “pull” containers from your local registry, which as they will not be configured to treat your registry as insecure will obviously get the ‘http response where https expected’ if they try to use it directly. This is easily fixed if you also run a website which has valid https certificates by simply proxying from your websites https site to the local container registry server, the external clients will then have a https connection and be able to pull from your registry.

Please note that I only cover “pull” by external clients here; personally I don’t see any reason why external clients should be pushing to your local registry so the example here denies the ‘push’ command. The example below should be added to a new conf file in your websites /etc/httpd/conf.d/ directory and will allow external clients to pull from your local repostory using the url you choose. I named my file /etc/httpd/conf.d/docker-registry.conf.

And you will notice I define a ‘push’ user; you really should not do that but an example should be complete :-). But if you are collaborating on products with users outside your local network you should be using a private project on one of the hosted git environments out there as they will (should) provide better security than anything covered in this port.

However with the configuration example below users can download from your private registry with commands such as “docker pull yourdomain.com:5043/imagename”. There will be no issues with complaints about ‘http responce when https expected’ as your webserver will be providing the https transport layer. Assuming you opened port 5043 on your server firewall and router port forwarding list of course. (tip: you can use your router to forward requests from port 5000 to 5043 (or any internal port) so treat 5043 as an example, not a recomendation).

# To create a push user...
# htpasswd -Bbn mark password >> /var/www/html/data/auth/httpd.htpasswd
# echo "pusher: mark" >> /var/www/html/data/auth/httpd.groups"
LoadModule headers_module modules/mod_headers.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule unixd_module modules/mod_unixd.soListen 5043
<VirtualHost *:5043>
   ServerName your.websitename.org
   SSLEngine on
   SSLCertificateFile /etc/letsencrypt/live/your.websitename.org/fullchain.pem
   SSLCertificateKeyFile /etc/letsencrypt/live/your.websitename.org/privkey.pem
   SSLCertificateChainFile /etc/letsencrypt/live/your.websitename.org/fullchain.pem
   SSLCompression off
   SSLProtocol all -SSLv2 -SSLv3 -TLSv1
   SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
   SSLHonorCipherOrder on
   Header always set "Docker-Distribution-Api-Version" "registry/2.0"
   Header onsuccess set "Docker-Distribution-Api-Version" "registry/2.0"
   RequestHeader set X-Forwarded-Proto "https"
   ProxyRequests off
   ProxyPreserveHost on
   # no proxy for /error/ (Apache HTTPd errors messages)
   ProxyPass /error/ !
   ProxyPass /v2 http://docker-local:5000/v2
   ProxyPassReverse /v2 http://docker-local:5000/v2
   <Location /v2>
      Order deny,allow
      Allow from all
      # match realm to the 'basic-realm' used by default in the registry container
      AuthName "basic-realm"
      AuthType basic
      AuthUserFile "/var/www/html/data/auth/httpd.htpasswd"
      AuthGroupFile "/var/www/html/data/auth/httpd.groups"
      # Read access to any users
      <Limit GET HEAD>
         Require all granted
      </Limit>
      # Write access to docker-deployer only
      <Limit POST PUT DELETE PATCH>
         Require group pusher
      </Limit>
   </Location>
</VirtualHost>

Installing and configuring the gitlab-ce container

This is also extremely simple as it comes bundled in a container. The only things to note are as everything is bundled into it, as such it is cpu and memory hungry, allow 3Gb of memory for this container alone.

It is also important that your local DNS (or /etc/hosts file) contain a seperate hostname to be used when accessing the gitlab-ce container as you do not want to use the servers hostname, this is important. Why it is important is discussed a little further on when discussing configuring ssh to treat gitlab-local references differently to normal ssh sessions. Along the lines of my using docker-local in the examples I will call the server gitlab-server and use gitlab-local for referencing the ip-address when refering to the gitlab-ce instance so I would have a /etc/hosts entry similar to the below.

192.168.1.nnn gitlab-server gitlab-local

The container image also benefits from going through ‘docker-squash’ as the image size can be decreased quite a lot, so ideally ‘docker pull’ the image and squash it before use; you can tag it as your own local registry copy and push that to your local regsitry so you are always working from a ‘known copy’; although having said that gitlab does release a lot of security fixes so you will want to periodically pull down the latest again.

Like the registry container I would recomend (it is really a requirement) that a bind volume mount is made for the data so it survives a container restart; you don’t want to lose all your data on a container restart.

Yet again I recomend downloading and using docker-squash on the image, and saving it in your local container registry to ensure you are using a known working copy of the container image as below. Plus the dockerhub container image is huge !.

docker pull gitlab/gitlab-ce                                   # pull the image down
docker image list                                              # get the imageid of the gitlab-ce container
docker-squash -t docker-local:5000/gitlab-ce:latest imageid    # use the imageid for gitlab-ce from the list command
docker push docker-local:5000/gitlab-ce:latest                 # save so you have a fixed/stable base image
docker image rm gitlab/gitlab-ce                               # remove the origional image

The docker-squash (as of the image on dockerhub on 2021/Feb/13) will be squashed from 2.15Gb to 2.1Gb, so not necessarliy worth doing… but you should still store it in a local registry and use that copy as you do not want to download 2Gb+ every time the dockerhub image gets a 1byte change in a config file; of course still download a new image when security pathes are implemented, but do not keep checking for updates to the latest.

You can then run the container with the command below, if you did not move the image to your local repository, or did not bother to manually pull it down at all, just replace the last line with ‘gitlab/gitlab-ce’ instead of ‘docker-local:5000/gitlab-ce:latest’ to use the dockerhub native image but do change the hostname to what you are using.

export GITLAB_HOME="/srv"        # REQUIRED ON LINUX SYSTEMS
# The :Z on volume mounts is for selinux systems to ensure docker can create the mounted volumes.
docker run --detach --rm \
   --hostname gitlab-local.mydomain.org \
   --publish 443:443 --publish 80:80 --publish 5522:22 \
   --name gitlab1 \
   --volume $GITLAB_HOME/gitlab/config:/etc/gitlab:Z \
   --volume $GITLAB_HOME/gitlab/logs:/var/log/gitlab:Z \
   --volume $GITLAB_HOME/gitlab/data:/var/opt/gitlab:Z \
   docker-local:5000/gitlab-ce:latest

Logon to the gitlab-ce container with your web browser (use HTTP, it is using port 80, do not use https as you have not setup any certificates, and in a home lab you do nor really need to publist port 443 in the command above) and setup yourself as the admin id, create ssh keys for yourself and create your first project. When creating each project it provides the git commands needed to push any existing project you have to it or create a new one from scratch so it is simple to use.

There is one additional step you should do on all the desktop Linux machines you use for development. Whether you installed this into a VM or a physical machine there is the issue of ssh port 22 (which git also uses by default) being used by ssh already for the server, which is why we mapped port 5522 to port 22 in the example run command above. Apart from that you probably keept the ssh keys created for you to use for the gitlab-ce container in a seperate file. The git command provides no option to change the port number, and you also do not want to have to enter the keyfile name every time you want to do a git push.

The solution is to use a custom ssh entry, so assuming you use “gitlab-local.mydomain.org” as the name assigned to the ip-address of the host running your container, you want git to connect to port 5522 on that address, and use your private key file id_ed25519_local_gitlab for the gitlab server, you simply create a file ~/.ssh/config and add the entries below to specify the connection rules for that server (the final “Host *” entry just means all hosts that do not match prior rules use the defaults in ssh_config and behave as normal).

Host gitlab-local.mydomain.org
  IdentityFile ~/.ssh/id_ed25519_local_gitlab
  Port 5522
Host *

With that entry set when you set the remote/origin fields for your new project in git to gitlab-local.mydomain.org:YourName/yourproject.git you can simply ‘git push’ as normal without needing to remember you are using non-defaults for that hostname… although you should make a note of it somewhere or when you get your next development server you will be wondering why git commands using git@gitlab-local.mydomain.org are being rejected by the server instead of being redirected to the container :-).

That entry in ~/.ssh/config of course only applies at the user level, you could also modify /etc/ssh/ssh_config to apply the rule to all users, but as that is likely to be overwritten by the next system update it is not recomended.

You will also notice I used the default port 80 for the gitlab web interface. So on that note, remember to open port 5522 (for git push/pull) and port 80 (for the gitlab web interface) on the host VM/server so you can reach the container application :-). Unless you want to create tls/https certs for the gitlab-ce instance you do not need to use port 443 but I included it in the example command above for completeness.

Installing and configuring the Jenkins container

This is also quite simple; however I would recomend you perform a customisation of the userid used.

By default the jenkins container will create and use a docker volume for its storage, allowing data to be retained across container restarts. If you are happy with that and are comfortable you know how to clone/backup/restore docker volumes the customisation step is entirely optional.

However as you may have quessed by now I like bind volume mounts to keep the data on the host filesystem. As the jenkins container data survives restarts as it is on a docker volume the only real advantage for me in using a bind volume mount in this case is that the data is able to be backed up in my regular bacula backups and I don’t need to worry about the complexity of backing up a docker volume.

The issue with a bind mount in this case is that the jenkins container has the jenkins user defined as uid 1000 which is the first system user created on a linux server, so your VM host will already have a user using that uid and if you define multiple nodes it could be a different userid owning that uid on each server.

Your options are to chown the filesystem you have chosen as the bind volume mount to that existing user on the host plus chown agent filesystems on each node to whatever userid you wish to run a jenkins agent under; or what I prefer to do is create a new ‘jenkins’ user on the host to own the filesystem and alter the container image to use the uid of that jenkins user within the container and also create a jenkins user with the same uid on all servers that will provide node services.

The later option is the better option as it provides a common userid/uid across all jenkins nodes and on nodes used to build docker containers adding the user ‘jenkins’ to the docker group provides more documentation that it is jenkins using it than if you had to use whatever userid you chose to run the agent under.

It should be noted that this step of altering the uid in the container image only affects the container and the host volume mount. The agent on a node can be started under any userid… it makes sense however to start it under a ‘jenkins’ uid on each node.

To update the container image create a Dockerfile as below replacing 6004 with the UID of the user you assigned to the ‘jenkins’ user on the host machine, change in both the Dockerfile and the following command for the build step as I like to keep track of major divergence changes in the tag where possible

FROM jenkins/jenkins:lts
USER root
RUN userdel jenkins
RUN useradd -u 6004 -d /var/jenkins_home -M --system jenkins
RUN chown -R jenkins:jenkins /var/jenkins_home

Then in the same directory as the Dockerfile run the command ” docker build -t localhost/jenkins:lts-uid6004 . ”

You should then if you decided to use a local container repository get the imageid using ‘docker image list’, tag the image as ‘docker tag imageid docker-local:5000/jenkins-lts-uid6004’ and push the image to your local container repository as a backup, and should be used instead of the localhost one, and untag the localhost one.

When starting the container note the DNS setting flags used, you need them but update then for your local DNS servers, the jenkins container needs to be able to resolve the host names used for your docker registry, source repository gitlab-ce host, and any servers you will be adding as nodes (remember the container does not have access to to the /etc/hosts file on its host server and any docker container by default is set yo only use 8.8.8.8 (google dns) (although I suppose you could map /etc/hosts into the container somehow) so your life will be much easier with a local DNS server [if you do not already have one just pick one of your servers not doing much with an up-to-date /etc/hosts file and start dnsmasq to provide one].

You should also note that as well as port 8080 being used for the web interface port 50000 is the default connection port for any agents on agent nodes. So ensure you open port 8080 and 50000 in the firewall of the VM running the jenkins container.

Now you are ready to run the container, with the command below.

if [ ! -d /var/jenkins_home ];
then
   mkdir /var/jenkins_home
   chown jenkins:jenkins /var/jenkins_home
fi
docker run -d \
  --dns 192.168.1.179 --dns 192.168.1.1 \
  -p 8080:8080 \
  -p 50000:50000 \
  -v /var/jenkins_home:/var/jenkins_home \
  --name jenkins1 \
  docker-local:5000/jenkins:lts-uid6004

Note that you could also include the option “–env JENKINS_OPTS=”–prefix=/jenkins” to make the URL to access jenkins http://xxx.xxx.xxx.xxx/jenkins/ rather than the default of http://xxx.xxx.xxx.xxx/ which is worth a mention here as if you plan to have your jenkins instance accessable behind a reverse proxy you will need a path to proxy on.

The first time you start the container use the ‘docker logs &ltcontainer-name&gt’ command (ie: ‘docker logs jenkins1’) to view the log messages, there will be a startup configuration password logged that you will need to logon to jenkins the for first time.

Note that logging on the first time takes you via a plugins install screen where you get to install lots of recomended plugins before it lets you through to the screen where you can create your first admin user.

Jenkins, and most of the documentation found for Jenkins (even youtube training examples) provides lots of information on building java and nodejs pipelines using maven/gradle/ant etc. so I assume those tools are already provided in the jenkins container image which is the ‘master’ node. I however am more interested in pipelines for building containers and compiling and packaging C programs for which it is hard to find documentation, so I have included a few examples at the end of this post.

You will need to create nodes to do any real work, for example to pipeline docker container builds you will need a node with docker installed. Setting up this first node example uses the host VM as a node as because you are running jenkins in a container under docker that server can immediately provide a docker build node :-).

In the ‘manage jenkins’ page there is a node management page, use that to define a new node which is the host running your container under docker. In the “labels” field give it a label indicating it can provde docker such as a label “docker-service”. While you can target a pipeline at a specific node/server it is better to target the pipeline at a label as you may add additional nodes later that can also provide docker. Select that you want to start the agent with a script.

At this point displaying the node will get to a page that has a button to start the agent and the java command that will be used is shown; the page should be visited and the button clicked from a browser on the server to run the node agent; guess what, the button won’t work for linux as the browser will instead want to download a jnlp file as it doesn’t know what to do with it, personally I think this is a good thing, do not start it from the browser !.

You will see that page the ‘agent’ text in the message is a link to a agent.jar file, so on your node server simply wget the url to pull the agent.jar file onto the node server.

At this point I would (having as recomended created a ‘jenkins’ user on every node) rename the agent.jar to jenkins_agent.jar and move it to /home/jenkins/bin plus create a script file containing the run command in the same directory. And always manually start it as the jenkins user… I say manually rather than in a systemd or init.d script as if the jenkins container is not running it will hammer your network (and log files) with connection retry attempts; start only when you are intending to use it and stop it when the jenkins container is stopped.

This is why starting it from the page in the web browser with a button click is a bad idea, it would run under the userid of whoever was running the browser session. When starting it manually never start the agent under the root user or a malicious Jenkinsfile could contain a command like ‘sh “/bin/rm /*”‘ which would work; limit the access the user starting the agent has.

Before the above step it is worth pointing out at this point that if setting up the docker node on the server running the jenkins container as the jenkins user was created with a home directory of the bind volume mount you will need to create a /home/jenkins on this server, on all the other nodes you would create the user with a home directory of /home/jenkins.

As this node will provide docker to pipelines remember to add the user jenkins to the docker group on the host server so the jenkins user can actually use docker.

You can then the ‘su’ to the jenkins user and run the command to start the agent, it will then show as available in the jenkins node list.

One additional note, that works immediately as you are effiectively on localhost. For adding additional nodes you will need to open firewall port 50000 on the host running the jenkins container to allow agents from other machines in your network to connect to your Jenkins container when they are started.

At this point you may be tempted to add all the software you could ever need to your VM running these CI containers and use only this one additional node to do everything. I would say don’t, you are probably just duplicating what you already have by doing so.

For example you may have a linux desktop where you are already doing a lot of GNU C/C++ development work, rather than install all the compilers onto the CI host or into a dedicated VM for a compile environment (and spending ages tracking down missind dependencies you installed on your development desktop and forgot about) just perform the extremely trival task of making your desktop a jenkins node as you already know it has all the tools needed.

And you will need other nodes for other functions as time goes by, for example I only build RPM packages at present but with CentOS no longer stable I have fired up a Debian server and are moving to building DEB packages instead; as like many people I do not plan on remaining on any RHEL stream until a viable non-vendor owned alternative to CentOS appears.

It is also worth mentioning source repositories here. We have installed gitlab-ce in a container and you will probably do most of your CI pipeline work from there, as that was the entire point of this exercise. However there is nothing to stop you from within your new jenkins container creating pipelines from other repositories such as the public github and gitlab sites as well should you also have existing github or gitlab repositories (which you should leave there if you do as a offsite backups are always a good thing).

Personally I make the source repositories available for public download as I don’t need to edit any of the files via the gitlab-ce interface and cannot be bothered with creating credentials. If you use private repositories you will need to set credentials for each source repository used when creating the pipeline.

It is also worth mentioning pipelines and nodes, specifiaccly what if you need to use multiple nodes in a pipeline. It is not always possible to perform all activities for a pipeline on a single node, for example I can do all compiles and rpm creation on a single node but from that node have to scp the resulting rpm to another node where the next pipeline step will run on that seperate node to move the rpm into a public repo and rebuild the repo index; to do so you must be aware that every ‘step’ in the pipeline will download the git project in its entireity, so even on the last node where it does nothing but need to move a file and run a createrepo command the entire git project is downloaded to that node anyway even though it will never be used. So unless you do require multinodes in a build do not select nodes at a step level but use a global node selection for the entire pipeline so the project is only downloaded once. Using multiple nodes can be inefficient not just for that reason but as you must move (scp) the stages of work between the nodes as needed you are really needing in the pipeline to refer to nodes by node name (hostname) rather than labels so you know exactly where to move things about, and where possible labels are preferred in a pipeline in preference to node names.

Also on pipelines, you would normally use a Jenkinsfile to define a pipeline, if you create a project expecting one and you add a source that does not have one in the project no build will occur; worth remembering if you wonder why your pipelines do not build.

As promised, a few Jenkinsfile examples

First a note on comments. You may use C style comments such as “/* multiline comments */” or for single line comments use “//” at the start of each line being commented. Mentioned as comments are always important :-).

Also it is important to note that these are examples; not working files (well they work perfectly well, but you need all the backend files in my source repositories for them to work for you, as there is a lot more to a pipeline than just a Jenkinsfile; you need all the code as well :-)..

The below Jenkinsfile will build a container image, the image will be tagged with the build number. Only when you are happy would you tag an image as ‘latest’ or give it a production version number and make it available.

Note that it requires that you have defined a node that has a label ‘docker-service’, in the setup steps above it was briefly discussed how to setup the host server running docker that provides the environment for the jenkins container as a docker-service node; but you can add as many as you want as long as one of the nodes are available.

pipeline {
   // Must run the build on a node that has docker on it
   agent { label 'docker-service' } 

   stages {
      // build the docker image
      stage("build") {
         steps {
            sh 'docker build -t localhost/ircserver:$BUILD_ID .'
         }
      }

      // squash the layers in the docker image
      stage("compress") {
         steps {
            echo "--- Squashing image ---"
            sh 'bash ./squash_image.sh localhost/ircserver:$BUILD_ID'
         }
      }

      // push the new image to the local repository
      stage("publish") {
         steps {
            // I would want to tag it as latest, and that is done by id not name
            echo "--- Would deploy all, but I won't, only new master branches ---"
            sh '''
               id=`docker image list | grep 'localhost/ircserver' | grep $BUILD_ID | awk {'print $3'}`
               if [ "${id}." != "." ];
               then
                  if [ "$BRANCH_NAME." == "master." ];
                  then
                     docker image tag ${id} docker-local:5000/ircserver:latest
                     docker push docker-local:5000/ircserver:latest
                     echo "Pushed to registry docker-local:5000 as ircserver:latest"
                     docker image rm docker-local:5000/ircserver:latest
                  else
                     docker image tag ${id} docker-local:5000/ircserver:$BRANCH_NAME
                     docker push docker-local:5000/ircserver:$BRANCH_NAME
                     docker image rm docker-local:5000/ircserver:$BRANCH_NAME
                  fi
                  # No longer needed on worker node
                  docker image rm localhost/ircserver:$BUILD_ID
               else
                  echo "No container image found to re-tag"
               fi
               # end of sh script
            '''
         }
      }
   } // end of stages

   post {
      // run if there was a failure, may be image layers left lying around
      failure {
         echo "*** Manully remove container and image workspaces ***"
      }
   }
}

The below example can be used to compile a C program. Ideally you would run it through a few “test” steps as well before packaging, but as they would be specific to your program you will need to add those yourself.

This example uses a global agent of none and uses step level selection of agents to run steps across multiple nodes.

pipeline {
   // must run on a server with gcc and package building commands on
   // then must run on public facing repo server to update the repo listings
   agent none
   environment {
      APP_VERSION="0.01"
      REPO_SERVER="10.0.2.15"
      REPO_DIR="/var/tmp/testrepo"
   }
   stages {
      stage("build") {
         agent { label 'gcc-service' }
         steps {
            sh 'echo "I AM IN $PWD"'
            sh 'make testprog MK_BRANCH_NAME=$BRANCH_NAME'
            echo 'What happened ?, if it worked well on the way'
         }
      }
      stage("package") {
         agent { label 'gcc-service' }
         steps {
            echo "Need to place rpm packaging commands in here"
            sh '''
               env
               echo "Still in directory $PWD, filelist is"
               machinetype=`uname -m`
               touch projectname-$APP_VERSION.${machinetype}.rpm
               ls
            '''
         }
      }
      stage("pushtorepo") {
         agent { label 'gcc-service' }
         steps {
            echo "Need to place scp commands here to copy to repo server"
            sh '''
               bb=`whoami`
               machinetype=`uname -m`
               echo "would run: scp projectname-$APP_VERSION.${machinetype}.rpm ${bb}@$REPO_SERVER:$REPO_DIR/${machinetype}"
            '''
         }
      }

      stage("creatrepo") {
         agent { label 'yumrepo-service' }
         steps {
            echo "And why so messy, parts must run on different servers"
            echo "Would run: cd $REPO_DIR;creatrepo ."
         }
      }
   } // end stages
}
Posted in Automation, Unix | Comments Off on Setting up a CI pipeline on Linux for your home lab

Is OpenIndianna a viable replacement for CentOS8, for me no

A post in my ongoing saga to find a replacement operating system for CentOS8. These posts are primarily notes I am making for myself on why I consider an OS an acceptable replacement or something I personally cannot use to replace my CentOS8 servers. That are certainly not detailed posts or even fully evaluated recomendations for anyone else… I am not fully evaluating each OS but only focusing on what I need and whether the OS provides it.

OpenIndianna is a production ready operating system, and depending upon what you want to use your servers for this is an option that should be considered as an OS; but not as a drop in replacement for CentOS8 as Oracle Linux and Debian can be (as documented in my earlier posts).

From the requirements I need, which is puppet and docker the good news is that puppet is available in the standard repositories. The bad news is that as OpenIndianna does not use a ‘Linux kernel’ docker is not available for this operating system.

Despite docker not being available OpenIndianna does of course provide Solaris Zones for application isolation, although they are fairly heavyweight compared to docker containers and of course configured completely differently and not truely isolated as the easiest way of networking a zone is to give it a public ip on your network.

Openindianna is available from the OpenIndianna download page if you are interested in giving it a try.

Also you will need to learn a completely new set of packaging tools, and a new set of system management tools (svcadm/zonecfg/zfs/zpool etc.) For example instead of “systemctl status httpd”, “systemctl enable httpd”, “systemctl start httpd”, “systemctl status httpd” you would use the below.

root@openindiana:/etc/apache2/2.4# svcs -a | grep apache2
disabled       21:38:40 svc:/network/http:apache24
root@openindiana:/etc/apache2/2.4# svcs svc:/network/http:apache24
STATE          STIME    FMRI
disabled       21:38:40 svc:/network/http:apache24
root@openindiana:/etc/apache2/2.4# svcadm enable svc:/network/http:apache24
root@openindiana:/etc/apache2/2.4# svcs svc:/network/http:apache24
STATE          STIME    FMRI
online         22:32:15 svc:/network/http:apache24
root@openindiana:/etc/apache2/2.4# 

However if you are used to creating service files for systemd you should have no trouble creating svc files for the OpenIndianna operating system.

Likewise the package management commands are different to CentOS, fortunately most are wrapped by the ‘pkg’ command. However

root@openindiana:/etc/apache2/2.4# pkg search php-pdo
INDEX      ACTION VALUE                                        PACKAGE
pkg.fmri   set    openindiana.org/web/php-56/extension/php-pdo pkg:/web/php-56/extension/php-pdo@5.6.35-2018.0.0.1
pkg.fmri   set    openindiana.org/web/php-54/extension/php-pdo pkg:/web/php-54/extension/php-pdo@5.4.45-2016.0.0.2
pkg.fmri   set    openindiana.org/web/php-55/extension/php-pdo pkg:/web/php-55/extension/php-pdo@5.5.38-2016.0.0.1
root@openindiana:/etc/apache2/2.4# pkg install php-pdo
Creating Plan (Solver setup): -
pkg install: No matching version of web/php-70/extension/php-pdo can be installed:
  Reject:  pkg://openindiana.org/web/php-70/extension/php-pdo@7.0.33-2020.0.1.5
  Reason:  This version is excluded by installed incorporation consolidation/userland/userland-incorporation@0.5.11-2020.0.1.12901
root@openindiana:/etc/apache2/2.4# 

It is a bit cleaner in a full package update in that it builds a new boot environment.

root@openindiana:/etc/apache2/2.4# pkg update
            Packages to remove:   1
           Packages to install:  10
            Packages to update: 481
       Create boot environment: Yes
Create backup boot environment:  No

DOWNLOAD                                PKGS         FILES    XFER (MB)   SPEED
Completed                            492/492   16174/16174  408.9/408.9  219k/s

PHASE                                          ITEMS
Removing old actions                       6025/6025
Installing new actions                     5528/5528
Updating modified actions                16031/16031
Updating package state database                 Done 
Updating package cache                       482/482 
Updating image state                            Done 
Creating fast lookup database                   Done 

A clone of openindiana exists and has been updated and activated.
On the next boot the Boot Environment openindiana-2021:01:02 will be
mounted on '/'.  Reboot when ready to switch to this updated BE.

It should be noted that after the full update the ‘pkg install php-pdo’ command shown above did actually work. However trying to install other packages I would need proved frustrating, the package management system seems to have no equivalent of the dnf/yum behaviour of simple selecting a match for what is already installed.

root@openindiana:~# pkg install php-opcache \
>   php-intl \
>   php-common \
>   php-soap \
>   php-mbstring \
>   php-gd \
>   php-json \
>   php-fpm \
>   php-xml \
>   php \
>   php-cli \
>   php-mysqlnd \
>   php-pecl-http \
>   php-bz2 \
>   php-zip \
>   php-pclzip

pkg install: The following pattern(s) did not match any allowable packages.  Try
using a different matching pattern, or refreshing publisher information:

        php-pclzip
        php
        php-mysqlnd
        php-pecl-http
        php-xml
'php-common' matches multiple packages
        pkg://openindiana.org/web/php-73/php-common
        pkg://openindiana.org/web/php-70/php-common
'php-fpm' matches multiple packages
        pkg://openindiana.org/web/php-73/php-fpm
        pkg://openindiana.org/web/php-70/php-fpm
'php-cli' matches multiple packages
        pkg://openindiana.org/web/php-73/php-cli
        pkg://openindiana.org/web/php-70/php-cli

Please provide one of the package FMRIs listed above to the install command.
root@openindiana:~# 

So you have to manually determine what is actually installed. Incidentally the ‘pkg update’ command upgraded everything to 70 so I could assume that the 73 is only partially implemented at this point or 73 would have been installed ?.

root@openindiana:~# pkg list | grep php
web/php-70/extension/php-pdo                      7.0.33-2020.0.1.5          i--
web/php-70/php-cli                                7.0.33-2020.0.1.5          i--
web/php-70/php-common                             7.0.33-2020.0.1.5          i--
root@openindiana:~#

Also it highlights that the packages I need to move my website to an OpenIndianna server may not exist making it even less likely it is a viable alternative for me.

You will also have seen that a full package update logged messages saying a new boot environment was created to boot from. So as well as learnming new package commands you must learn new OS management commands as a result of wanting to install packages. As a side note it is interesting that a new BE has a new copy of /var as I’m not aware of any OS configuration files that live under there so just retaining the existing /var with website pages, mysql/mariadb databases, logfiles etc. would seem to me to make more sense that replicating them all in a new boot environment. But then what do I know; and this post is not on how to use OpenIndianna but on why I would find it difficult to replace a CentOS server farm with OpenIndianna.

root@openindiana:~# beadm list
BE                     Active Mountpoint Space Policy Created
openindiana            -      -          7.65M static 2020-08-27 14:14
openindiana-2021:01:02 NR     /          5.76G static 2021-01-02 03:35

root@openindiana:~# zfs list
NAME                                    USED  AVAIL  REFER  MOUNTPOINT
rpool                                  9.90G  28.4G    33K  /rpool
rpool/ROOT                             5.77G  28.4G    24K  legacy
rpool/ROOT/openindiana                 7.65M  28.4G  2.43G  /
rpool/ROOT/openindiana-2021:01:02      5.76G  28.4G  2.52G  /
rpool/ROOT/openindiana-2021:01:02/var  1.94G  28.4G   910M  /var
rpool/ROOT/openindiana/var             2.49M  28.4G   956M  /var
rpool/dump                             2.00G  28.4G  2.00G  -
rpool/export                             77K  28.4G    24K  /export
rpool/export/home                        53K  28.4G    24K  /export/home
rpool/export/home/mark                   29K  28.4G    29K  /export/home/mark
rpool/swap                             2.13G  30.5G  25.5M  -
root@openindiana:~# 

On the firewall side OpenIndianna uses “IP Filter” as the firewall solution. As such users coming from a CentOS environment where iptables and NF tables have been used (either hidden from the user behind firewalld or used manually) will have to learn a new set of commands; and rewrite any customised automated firewall deployment and checking tools used.

It should also be noted that I did previously use solaris-x86 (back in the day when SUN still owned it) and OpenIndianna and found everything I needed as far as applications/packages go compiled with the GCC compiler quite happily from source so with a little bit of work everything needed is available… apart from Docker of course that needs a Linux kernel. I also found ZFS quotas extremely useful, athough I only played with zones as they provided no great benefit to me. It most certainly is a good solution if you are looking for a ‘all-in-one’ server for you applications, not so great if you are looking for application isolation or cloud deployment.

One thing that must be mentioned is that I have found it impossible to get OpenIndianna running under OpenStack (can do through the installation procedure and install, but not boot afterward). No ‘cloud images’ are available and the repositories do not seem to contain a ‘cloud-init’ package for it either (at least a ‘pkg search’ cannot find one). It does not support as much hardware as linux distributions do so you may run into issues, although it will run under linux KVM with the issue that on a reboot the KVM instance goes into a paused state and you must issue virst reset xxx and virsh resume xxx to let the reboot continue which makes it not the ideal candidate for an OS to run under KVM. This is also unlikely to ever be possible as this operating system is simply not designed for cloud use, it is a server operating system that runs best on native bare hardware.

For me personally I have been isolating applications I use (those that do not need access to the entire system anyway) into standard containers for docker and K8 use, so the inability to use docker prevents me from using this as a replacement for CentOS8; docker has become such a part of my application deployment I have even needed to run a local registry and moving applications from containers back to local server applications seems counter-intuative to me.

So for me it is not an option as a ‘quick’ replacement for CentOS8. For anyone setting up new server environments from scratch and no intention of using containers (although zones are available) it is a good option.

A note for desktop users; I have only ever used server installs so I do not know how it behaves as a desktop, however it is a good bet that if you rely on applications from rpmfusion, copr, or even snap packages you will probably find it wanting. I would consider it a ‘server’ OS.

Posted in Unix | Comments Off on Is OpenIndianna a viable replacement for CentOS8, for me no

Is openSUSE Leap a viable replacement for CentOS8, for me no

A post in my ongoing saga to find a replacement operating system for CentOS8. These posts are primarily notes I am making for myself on why I consider an OS an acceptable replacement or something I personally cannot use to replace my CentOS8 servers. That are certainly not detailed posts or even fully evaluated recomendations for anyone else… I am not fully evaluating each OS but only focusing on what I need and whether the OS provides it.

OpenSUSE ‘leap’ Seems to have a support (LTS) cycle of around 18 months between point releases.
‘Leap’ is the more stable release, there is also the ‘Tumbleweed’ option which is updated more frequently with ‘stable’ packages and is more for testing the latest features not in the more stable ‘Leap’ release; potentially a more stable version than CentOS but in the same place in the new position in the development stream CentOS ‘stream’ has been placed in.

I decided to look at the ‘Leap’ release 15.2 has now been released. The ISOs for all platform types are available at http://download.opensuse.org/distribution/leap/15.2/.

Do not for evaluation purposes reply “yes” to the do you want to enable network repositories now prompt at install time. If you do it will try to download over 4Gb of data (it seems like it will use the network repositories in preference to what is on the install media). Reply “no” and it will install from the install media.

Also I could find nowhere to define a static network setup duting installation, so it installed using dhcp addressing which I do not want. Also after installation iin the “Yast Network Settings” you will see that by default sets the hostname based upon what if gets from the dhcp server, and there is nowhere to set a static address. Also under “settings/network” tehre is no way of setting a static ip-address. There is documentation on how to do so from a GUI interface using “Yast Network” configuration at https://doc.opensuse.org/documentation/leap/reference/html/book-opensuse-reference/cha-network.html (tip: search the page for “set a static”) however it does not work as any attempt to open the overview tab just throws up an error saying it is managed by NetworkManager. After much googling in the Yast Network configuration change the network from networkManager to Wicked and then you can set a static ip-address and set the hostname (took a lot of googling to find that, god knows how on a server (no gui) you would do it from the command line) and you must still use the hostname/dns tab to set a static hostname and define custom dns settings; despite it saying changes are applied there is no change in ipaddress and a ‘systemctl retstart NetworkManager’ and ‘systemctl retstart network’ have no effect and a reboot is needed to pick up the change.

There are probably too many incompatabilities between this and other *nix’s for it to be an immediately viable alternative (specifically package management). Examples

  • to find what package containes ifconfig the command is “cnf ifconfig”… that command does however tell you the exact command to use to install the package which is nice
  • to install the package the command to use is “zypper install net-tools-deprecated”

While I am used to dnf/yum/rpm, and can manage to fight my way through apt/dpkg, do I really want to learn a completely new packaging system just to replace a CentOS8 server; not at the moment.

The openSUSE community do provide cloud images (including for openstack) which is one of my requirements for a replacement OS. These can be found at https://download.opensuse.org/repositories/Cloud:/Images:/Leap_15.2/images/ although I have not tested one.

Docker is available for openSUSE. Installation instructions for Yast2 gui and command line options (and a workaround for a bug where it ignores brtfs quotas) is at https://en.opensuse.org/Docker.

Mariadb is available, a walkthrough on how to install it is at https://computingforgeeks.com/how-to-install-mariadb-on-opensuse/ and involves adding a seperate epository.

Puppet-agent is not available for openSUSE Leap 15.2, documented at https://software.opensuse.org/package/puppet with the comment “There is no official package available for openSUSE Leap 15.2”. So to replace many servers would be a lot of manual work.

So while openSUSE looks interesting as a replacement for centOS8, it is not really an option if you are looking for a quick and easy replacement as there are new packaging commands to learn, and the major detail that puppet-agent is not supported (yet) makes replacing more than a single server impractical for me.

If you are not replacing an existing rhel based server farm but looking to implement a new solution from scratch then this OS could be considered as an option for you. Although one thing to consider is that leap point releases seem to become available at around 18 month intervals so LTS can be considered as 18 months (the commercial offering has LTS of 10 years betwen major releases, but of course as a CentOS replacement we are only looking at free options).

Posted in Unix | Comments Off on Is openSUSE Leap a viable replacement for CentOS8, for me no

Is Debian a viable alternative to CentOS8, for me yes

Since the RedHat announcement that CentOS8 ‘stable’ is becoming a test system on centOS8 ‘stream’ rather than being provided as a stable system anymore many people are looking for alternative operating systems.

I have already covered in the previous post how to successfully with minimal effort convert a CentOS8 system to Oracle Linux 8. This post is on whether for my use Debian can also be considered an alternative. The answer is yes, and these are my notes on that.

So this minimal post is on the steps needed to create a Debian server that provides all the functionality of one of my more complex servers.

Install a new bare Debian10 (buster) system, if you intend to use it as a web server select minimal webserver at this time as well to install apache2.

This entire post is based upon my evaluation of installing a Debian10 system to replace a CentOS8 one; that was running a puppet-agent, docker for container support, mariadb, a bacula-client for backups etc. Basically a rather complicated system.

Obviously you should set a static ip-address for the server.

Once the system is installed the below commands create an environment that is from initial testing a workable clone of my centOS8 system.

apt install net-tools               # <=== for ifconfig
apt update
apt upgrade
#
# mariadb
apt install mariadb-server
#
# nrpe
#    notes on nrpe
#       on CentOS as package nrpe managed with 'systemctl xx nrpe, use systemctl xx nagios-nrpe-server on debian
#       on centOs plugins were /usr/lib64/nagios/pluins, on Debian /usr/lib/nagios/plugins
#       on CentOS custom commands were defined in disrectory /etc/nrpe.d, on debian in disrectory /etc/nagios/nrpe.d
#    those notes are important as puppet rules for a rhel system cannot be resused on debian, in a mixed server
#    environment there will be a lot if if/else and evan template customisations to cope with rhel and debian
#    (this is the most incompatible application I have found in a conversion from rhel to debian)
apt install nagios-nrpe-server
#
# Docker-ce
apt-get remove docker docker-engine docker.io containerd runc
apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
apt-update
apt-get install docker-ce=5:20.10.1~3-0~debian-buster docker-ce-cli=5:20.10.1~3-0~debian-buster containerd.io
#
# puppet agent
wget https://apt.puppetlabs.com/puppet7-release-buster.deb
dpkg -i puppet7-release-buster.deb
apt-get update
apt install puppet-agent
#
# Modules I need for my website
# note: centos used php-pecl-zip, not available in debian; so adding all available pecl and zip php modules
apt install \
  php-pdo \
  php-opcache \
  php-intl \
  php-common \
  php-soap \
  php-mbstring \
  php-gd \
  php-json \
  php-fpm \
  php-xml \
  php \
  php-cli \
  php-mysqlnd \
  php-pecl-http \
  php-bz2 \
  php-zip \
  php-pclzip 
a2enmod proxy_fcgi setenvif
a2enconf php7.3-fpm
systemctl restart apache2
#
# bacula-client
#   notes: I let puppet do this and perform all configuration needed.
#          if not using a congig management tool you will have to customise
#          to define stoage and director servers
apt install bacula-client
#
# Done

I also copied across a mariadb full database dump from my centOS8 server and loaded it into the Debian mariadb server with no issues.

I also tested containers built on Fedora33 that were running on my CentOS8 system in rather complex network configurations and they ran without issues on Debian.

The key things to note (mainly for automated configuration rules for software deployment) are

  • On CentOS8 NRPE is packaged as 'nrpe', service nrpe.service,
    plugins were /usr/lib64/nagios/pluins, custom commands in /etc/nrpe.d
    On Debian NRPE is pacaged as 'nagios-nrpe-server', service nagios-nrpe-server.service,
    plugins are in /usr/lib/nagios/pluins, custom commands in /etc/nagios/nrpe.d
  • On CentoS8 the webserver is package 'http' and service httpd.service.
    On Debian the package is 'apache2' and service apache2.service
  • There is no 'wheel' group on Debian. If adding admin users probably best to put them in the 'sudo' group
  • Most of the changes I was able to implement in puppet fairly easily by wrapping the existing configurations
    in a "if ( $facts['os']['family'] == "RedHat" ) { }" block follwed by
    "elsif ( $facts['os']['family'] == "Debian" ) { }" and a default catchall else block for other operating systems I may test. It should be noted that the if/elsif/else block had to be implemented in quite a few rules

It should also be noted that neither iptables ot firewalld are installed by default; that suits me perfectly as I use iptables on almost all servers internet facing and firewalld on desktops and internal servers behind firewalls that do not need the explicit fine grained detail iptables provides; so not having to unistall either and just selcting the one I wish to use is an advantage.

I also have not actually run a full clone of any of my servers on Debian. While there should be no issues (tested to the point I should only need to copy over all the web directories) all my alternatives to CentOS evaluations are being done on minimally sized servers, a full test only when I have decided on which OS to move to.

Debian OS releases have shorter support cycles than Oracle Linux (which uses RHEL as a base so should have LTS until 2029). For the latest release of Debian (buster) it moves from debian support in 2022 to volumteers maintaining security support until 2024. Effectively a rhel based release can keep running for 7-8 years and a Debian based one 2-3 years before a major OS upgrade is needed (reference: https://wiki.debian.org/LTS.

So while Debian is a workable replacement for CentOS8 anyone looking for stability is still likely to move toward Oracle Linux.

I still intend to evaluate openSUSE in a later post also, as I wish to look at as many alternatives as possible. However openSUSE 'Leap' (the more stable release, there is also a 'tumbleweed' release for those wanting changes faster) seems to require upgrading between point releases at around 18 month intervals. The commercial release has support for 10 years with each release but of course for CentOS8 replacements I am only looking at the free alternatives. But I may correct that statement as I do more research into openSUSE in that later post.

Posted in Unix | Comments Off on Is Debian a viable alternative to CentOS8, for me yes

The Oracle conversion script to convert CentOS to Oracle Linux, and an alternative

As mentioned in my previous post there is a script supplied to convert CentOS systems to Oracle Linux, available at https://github.com/oracle/centos2ol. As mentioned in that post it is not safe to use at the currect time.

At the end of this post I will list steps that have worked for me that you should use in preference to this script. It’s at the end as this post is primarily on why not to use the supplied conversion script.

Obviously as Oracle Linux relies on RedHat continuing to follow the software license guidelines and make available all the sources they modify it can only be hoped they continue to do so to ensure Oracle Linux remains a viable alternative to CentOS. However as the RedHat announcement makes CentOS unsafe for production work any more Oracle Linux is the currently available free alternative that requires the least conversion work.

As of 26 December 2020 using that script on a fresh centOS8 install from CentOS-8-x86_64-1905-dvd1.iso results in the below.

The error that stopped the converted system booting after the conversion script was run was

Failed to switch root: Specified switch root path '/sysroot' does not seem to be an OS tree. os-release file is missing.

So I built a new CentOS8 KVM instance as a bare server install. Prior to running the conversion script

[mark@c8toOL8-test etc]$ cat os-release
NAME="CentOS Linux"
VERSION="8 (Core)" 
ID="centos"
ID_LIKE="rhel fedora" 
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)" 
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

[mark@c8toOL8-test etc]$ ls -la *release
-rw-r--r--. 1 root root  38 Aug 14  2019 centos-release
-rw-r--r--. 1 root root 420 Aug 14  2019 os-release
lrwxrwxrwx. 1 root root  14 Aug 14  2019 redhat-release -> centos-release
lrwxrwxrwx. 1 root root  14 Aug 14  2019 system-release -> centos-release
[mark@c8toOL8-test etc]$

[mark@c8toOL8-test etc]$ ls /etc/yum.repos.d
CentOS-AppStream.repo   CentOS-CR.repo         CentOS-fasttrack.repo   CentOS-Sources.repo
CentOS-Base.repo        CentOS-Debuginfo.repo  CentOS-Media.repo       CentOS-Vault.repo
CentOS-centosplus.repo  CentOS-Extras.repo     CentOS-PowerTools.repo
[mark@c8toOL8-test etc]$

After running the supplied conversion script we are left with

[root@c8toOL8-test centos2ol]# cd /etc
[root@c8toOL8-test etc]# cat os-release
cat: os-release: No such file or directory
[root@c8toOL8-test etc]# ls *release
ls: cannot access '*release': No such file or directory
[root@c8toOL8-test etc]# ls /etc/yum.repos.d
switch-to-oraclelinux.repo

So the conversion script seems to get only part of the way through, far enough
to wipe out CentOS but not far enough to make OL usable.

So do not use the oracle conversion script.

This does not mean that the script may not become usable at some future point, it is just not safe to use at present.

Unrelated information

On a fresh Oracle Linux 8 install these are the files created

[mark@oracle8-freshinstall etc]$ cat os-release
NAME="Oracle Linux Server"
VERSION="8.3"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="8.3"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Oracle Linux Server 8.3"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:8:3:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://bugzilla.oracle.com/"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.3
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.3

[mark@oracle8-freshinstall etc]$ ls -la *release
-rw-r--r--. 1 root root  32 Nov  5 12:58 oracle-release
-rw-r--r--. 1 root root 479 Nov  5 12:58 os-release
-rw-r--r--. 1 root root  45 Nov  5 12:58 redhat-release
lrwxrwxrwx. 1 root root  14 Nov  5 12:58 system-release -> oracle-release
[mark@oracle8-freshinstall etc]$ 

[mark@oracle8-freshinstall etc]$ ls /etc/yum.repos.d
oracle-linux-ol8.repo  uek-ol8.repo

An alternative upgrade method that seems to work

This method was suggested in a response to the origional CentOS moving to be stream only post at https://blog.centos.org/2020/12/future-is-centos-stream/ by commenter “Phil”. I have edited it to what works for me (which was basically correcting ‘centos-release’ and highlighting the importance of needing yum-utils installed before disabling the centos repositories; plus the reset module step I needed to use.

setenforce 0
dnf -y install yum-utils       # <---- this MUST be installed
repobase=http://yum.oracle.com/repo/OracleLinux/OL8/baseos/latest/x86_64/getPackage
wget \
  ${repobase}/redhat-release-8.3-1.0.0.1.el8.x86_64.rpm \
  ${repobase}/oracle-release-el8-1.0-1.el8.x86_64.rpm \
  ${repobase}/oraclelinux-release-8.3-1.0.4.el8.x86_64.rpm \
  ${repobase}/oraclelinux-release-el8-1.0-9.el8.x86_64.rpm

rpm -e centos-release --nodeps
dnf --disablerepo='*' localinstall ./*rpm
:> /etc/dnf/vars/ociregion
dnf remove centos-linux-repos
dnf --refresh distro-sync --allowerasing --nobest

The last dnf command results in

[root@oracle8 ~]# dnf --refresh distro-sync --allowerasing --nobest
Oracle Linux 8 BaseOS Latest (x86_64)                                                                                                            28 kB/s | 2.7 kB     00:00    
Oracle Linux 8 Application Stream (x86_64)                                                                                                       36 kB/s | 3.1 kB     00:00    
Oracle Instant Client for Oracle Linux 8 (x86_64)                                                                                                28 kB/s | 2.5 kB     00:00    
Latest Unbreakable Enterprise Kernel Release 6 for Oracle Linux 8 (x86_64)                                                                       26 kB/s | 2.5 kB     00:00    
Dependencies resolved.
The operation would result in switching of module 'llvm-toolset' stream 'rhel8' to stream 'ol8'
Error: It is not possible to switch enabled streams of a module.
It is recommended to remove all installed content from the module, and reset the module using 'dnf module reset ' command. After you reset the module, you can install the other stream.

Easily fixed with

[root@oracle8 ~]# dnf module reset llvm-toolset
Last metadata expiration check: 0:01:22 ago on Sat 26 Dec 2020 11:41:27 NZDT.
Dependencies resolved.
================================================================================================================================================================================
 Package                                   Architecture                             Version                                     Repository                                 Size
================================================================================================================================================================================
Resetting modules:
 llvm-toolset                                                                                                                                                                  
Transaction Summary
================================================================================================================================================================================
Is this ok [y/N]: y
Complete!

After which rerunning the “dnf –refresh distro-sync –allowerasing –nobest” works.

There was one failure

Failed:
  pcp-webapi-4.3.0-3.el8.x86_64 

This left “package-cleanup –problems” reporting problems for that; resolved with “rpm -e pcp pcp-webapi pcp-mnager –nopreun” (noreun was required as the pre-uninstall script kept erroring).

“package-cleanup –orphans” showed quite a few entries, these are packages installed that are not available from the configured repositories; and included things like buildah and podman that certainly should be.

“dnf autoremove” also listed a few packages I would want to keep as available for removal.

The supprising issue was that “shutdown -r now” refused to shutdown, “init 6” has no effect. Neither did “halt” or “reboot”; too many interface changes ?. I had to trigger a ‘force-off’ poweroff from the virt-manager interface and start the KVM again from there. However after that first forced restart reboots were behaving normally again.

So that would be my recomended upgrade path, not the script on github.

Future posts planned

While conversion to Oracle Linux is the least disruptive as far as compatibility goes, I will also be looking at getting tools like docker-ce, puppet-agent, bacula-client etc running on Debian; which if successful may result in a lot less rhel based posts here and a lot more debian based ones.

Posted in Unix | Comments Off on The Oracle conversion script to convert CentOS to Oracle Linux, and an alternative

Is Oracle Linux a viable alternative to CentOS

By now you are all aware of the RedHat/IBM decision to destroy CentOS as a viable stable platform. Oracle has been suggested on many Forums as an alternative.

While some responses on forums indicate a belief that Oracle Linux is based on CentOS and therefore would also be unstable in the future the Oracle blogs themselves indicate their builds are from the RedHat sources not CentOS, and generally they release updates to RHEL faster than done previously by CentOS.

Oracle themselves are aware they have been touted as an option, and have even published a script that can be used to convert a running CentOS system to a Oracle system, for CentOS8 to Oracle Linux 8 that script is located at https://github.com/oracle/centos2ol. DO NOT USE THAt SCRIPT, see update notes at end of this post.

The key thing is the script is for CentOS systems already running, what about deploying Oracle Linux 8 from scratch then. The main issues I have are

  • the install DVD media is 8.6Gb, double the size of CentOS
  • desktop installs require accepting a license agreement, hands off install may be difficult
  • oracle logos are all over the place
  • there is no ‘epel-release’ package, you must instead ‘dnf install oracle-epel-release-el8’, that is not obvious but obviously must be installed to obtain most of the packages everyone needs such as nrpe or even utilities like iftop
  • where I refer to a ‘desktop’ install in this post it is the default install software selection of ‘server with gui’; as in a bit of a rush as I was only installing to test for this post I did not change the default to ‘Workstation’
  • there appear to be no publically available Oracle Linux cloud images (see below paragraph)

Many CentOS users would deploy to an in-house cloud, normally OpenStack. Images that will work under OpenStack are listed at https://docs.openstack.org/image-guide/obtain-images.html and Oracle Linux is not one of them. The CentOS stable images before Redhat moved CentOS to “stream” are there. Also listed are RHEL ones but a Redhat Enterprise license subscription is needed to download those. So the options now are Debian, Fedora, Ubuntu, SUSE or unoffical images for BSD based servers.
Oracle Linux images seem to be only provided for “Oracle cloud” and not publicly available for those running OpenStack. A google search finds lots of examples on how to run OpenStack on Oracle Linux servers, nothing on how to run Oracle Linux under OpenStack. Sorry Oracle, most corporations have OpenStack as internally hosted ‘lab’ cloud systems, no AWS/Google/Azure/Oracle interfaces in a ‘lab’ environment.

However I have checked and ‘cloud-init’ is a package available with Oracle Linux so it should be simple to create your own custom images. Or if you don’t want the effort launch a CentOS8 instance, use the Oracle provided script to convert it to OL8, remove all the files indicating cloud-init has already run, shutdown and snapshot to use as a new cloud image.

For desktop users it should be noted that neither of the addtional required steps for CentOS8 or RHEL8 (enabling powertools or codeready-builder) recommended to be issued as part of enabling the rpmfusion repositories work on Oracle Linux 8. However even without those the repositories seem to work (at least I was able to install vlc) although not being able to complete all the setup steps for the repository may result in issues later on. Obviously rpmfusion is a repository that must be accessable to use the system as a ‘desktop’. Setup instructions for that are still at https://rpmfusion.org/Configuration.
Update:26Dec2020: the OL equivalent to powertools is ol8_codeready_builder

Podman and Docker

For developers podman and buildah are installed by default on a desktop install (and server installs with ‘container management tools’ selected), and if you prefer docker Oracle have an article on installing docker on OL8 at https://oracle-base.com/articles/linux/docker-install-docker-on-oracle-linux-ol8which does not work without an additional flag as OL8 packages installed for podman are incompatible with the docker ones. You must allow existing packages to be removed, using the –allowerasing option to install docker works and shows

===========================================================================================================
 Package                    Arch    Version                                       Repository          Size
===========================================================================================================
Installing:
 docker-ce                  x86_64  3:20.10.1-3.el8                               docker-ce-stable    27 M
Installing dependencies:
 containerd.io              x86_64  1.4.3-3.1.el8                                 docker-ce-stable    33 M
     replacing  runc.x86_64 1.0.0-68.rc92.module+el8.3.0+7866+f387f528
 docker-ce-cli              x86_64  1:20.10.1-3.el8                               docker-ce-stable    33 MCentOS-8-x86_64-1905-dvd1.iso
 docker-ce-rootless-extras  x86_64  20.10.1-3.el8                                 docker-ce-stable   9.1 M
 libcgroup                  x86_64  0.41-19.el8                                   ol8_baseos_latest   70 k
Removing dependent packages:
 buildah                    x86_64  1.15.1-2.0.1.module+el8.3.0+7866+f387f528     @AppStream          28 M
 cockpit-podman             noarch  18.1-2.module+el8.3.0+7866+f387f528           @AppStream         4.9 M
 podman                     x86_64  2.0.5-5.0.1.module+el8.3.0+7866+f387f528      @AppStream          51 M
 podman-catatonit           x86_64  2.0.5-5.0.1.module+el8.3.0+7866+f387f528      @AppStream         752 k

Transaction Summary

So while most developers will be using podman on their desktops servers would normally run docker (in prod as a docker swarm) or kubernetes as the container environments. However the –allowerasing option does install a working docker so you can use either.

I would have added a comment to the article highlighting that requirement but going to the article comments page results in the error “Prepared Statement Error: Table ‘./oraclebasecms/cms_page_comment_uuids’ is marked as crashed and should be repaired “; I would hope the Oracle Linux development teams do a better job that the website database teams. But the steps are

dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
dnf install -y docker-ce --nobest --allowerasing

I have tried an image built on Fedora33 with podman that runs happily under docker on centOS8, and yes testing shows it also runs happily on Oracle Linux 8 with the UEK kernel.

Puppet

Puppet agent also installs perfectly well with

rpm -Uvh https://yum.puppet.com/puppet7-release-el-8.noarch.rpm
dnf search puppet-agent
dnf install puppet-agent

Minimal changes were needed to puppet rules on my configuration server as I already had a lot of ‘exceptions’ coded for packages missing in CentOS8 so was just a case of changing all rules that refered to centos from … $facts[‘os’][‘name’] == “CentOS” and $facts[os][release][major] == “8” … to … ($facts[‘os’][‘name’] == “CentOS” or $facts[‘os’][‘name’] == “OracleLinux”) and $facts[os][release][major] == “8” …; up until this point I do not have enough mixed server OSs to use case statements like I should :-)

Once I had sorted out the new name Oracle uses for the ‘epel-release’ starting the puppet agent installed and configured all the applications and tools I use on a CentOS8 server without issue on the Oracle Linux server.

I have not tried puppetserver, just the agent. testing puppetserver will be a migration from C8 to OL8 on that machine and will probably be the last converted.

Other tools

Testing puppet also installed a lot of other tools such as the bacula-client, nrpe etc. which all seemed to start correctly.

I like to ssh into remote servers with X-11 forwarding on to run GUI apps. To allow that from a OL8 server install, “dnf -y install gdm”. It is enabled after install by default but to start it without rebooting “systemctl start gdm”. Annoyingly that makes the console GUI so also “dnf -y install gnome-terminal xterm” to get any work done… after rebooting the console behaves and remains in tty mode while gdm runs and allows remote users sshing in to run gui apps.

What I have not tested – disclaimer

As noted tools like bacula-client install and start correctly; however I do not have the storage available to actually test a backup works. Similarly with other applications I do not want activity generated from the OL8 test systems I have been throwing up and tearing down.

Just because an application starts does not mean it will work. But it seems promising.

Summary

A basic summary is that OracleLinux does seem to be able to replace CentOS from a fresh install point of view, everything seems to be there. Do not use the conversion scriot, see updates below.

Next steps

My next post is likely to be on running the conversion script created by Oracle on a C8 test system I fire up. They recommend disabling all non-core repositories and I have quite a few such as docker and puppet; so that will be interesting. I will try on a fresh C8 install, then a really complicated KVM instance, and see what happens. If it turns into a mess I will certainly post on it (assuming the mess is not on this webserver of course… backup time).

Update 2020/12/25 20:21: do not use the oracle provided conversion script. I created a test CentOS8 KVM instance from install media CentOS-8-x86_64-1905-dvd1.iso using a standard server install, no third party repositories were used. A git clone of the conversion script project (following the download script only links results in the webpage being saved rather than the script so you have to clone or download the git project) and running the script results in the test system rebooting into emergency mode; the test system is unusable. That script is truely a BETA. The error on boot is “Failed to switch root: Specified switch root path ‘/sysroot’ does not seem to be an OS tree. os-release file is missing.” and there will be a follow up post on my investigations into that.

So the summary update is, if you are willing to install from scratch and migrate applications Oracle Linux is an option for replacing CentOS servers; but despite posts made by Oracle on it being easy to convert a CentOS system to Oracle Linux it is not yet safe to attempt to do so. VM replacement rather than conversion is the only safe option… buit then if you are switching to Ubunto, Debian or SUSE you will be following the replacement rather than conversion path anyway.

Posted in Unix | Comments Off on Is Oracle Linux a viable alternative to CentOS

Still wanting to play those old SWF Flash files browsers no longer support ?

Want to be able to use those old Shockwave Flash files again ?

As we all know all browsers are dropping support for Flash due to its security risks. This can be an issue if you have a large collection of shockwave flash (SWF) games, or even something more useful lying about.

If you do have such files lying about they are not totally useless, as long as the SWF files are the old AV1 format (AV2 [actionscript 3] became available in 2006 and mandatory to use around 2013 so more recent files will not run yet).

Enter Ruffle (https://ruffle.rs/), a Flash Player emulator written in Rust and made available as webassembly and javascript for all modern browsers with webassembly support. This allows those old flash files to run in a sandboxed environment.

It provides, it order of what I find important

  • a web server can be configured to provide applicationtype wasm (some servers support it by default, apache must have it explicitly configured) and adding a single one line ‘script’ entry to any webpage is enough to allow the webserver to display working flash content to users without the users needing to install anything on their client machines/browsers to view the flash content
  • a browser extension to allow flash content to run on the client browser, for those sites that do not publish ruffle from the server webpage, so old flash sites will work for you again (although by now you will have probably un-bookmarked the old sites that were unusable for you until now)
  • a standalone command line client to play SWF files from your desktop

Ruffle is still in development. It does not have all the features of AV1 implemented and work on AV2 compatibility while begun is not likely to be available for quite some time; as Ruffle is of course being developed entirely by volunteers. As such it produces nightly builds so you will probably want to check regularly and get updates periodically. It is under active development as can be seen from the reported issues although most issues seem to relate to specific swf files.

In the list above order of importance for me is of course based on the fact I run a web server so wish to be able to server content without visiting browsers needing to have extensions installed. Having said thatI did have to trawl through old backups to find any flash files to test this with as I had cleaned them all off my server when flash support was dropped from browsers (grin). But find some I did, along with the old html that used to show them, and yes adding that one script line does make most of them availble to browsers again.

The standalone client for linux works well also.

I have not tried the browser extention as my webserver now serves the files in a usable way.

This is a very interesting project, so if you have any skills in Rust or javascript jump in and help.

For those running webservers that have old archives SWF content, you may want to look at Ruffle and un-archive any useful or fun files again.

It should be notes that I have not been able to get SWF files such as FlowPlayer and flvplayer to work under ruffle in order to play ‘FLV’ files rather than swf ones; but I still have to try exotic combinations such as trying to provide CAB files so it may not be impossible; and as mentioned Ruffle is still under development so they may just magically (after a lot of work by the volunteer developers) become usable at some point.

Posted in Unix | Comments Off on Still wanting to play those old SWF Flash files browsers no longer support ?

Installing OpenStack Ussuri in a multicompute node configuration in your home lab

This post covers installing from the RDO project documentation that can be found at https://www.rdoproject.org, it uses the ‘packstack’ tool covered at https://www.rdoproject.org/install/packstack with the main changes in this post being defining additional compute nodes plus installing heat support as I use heat patterns a lot.

It also covers implementing connectivity from your OpenStack private networks to your existing network; in the correct order as the document on the RDO site to achieve this does not mention the need to install OpenVswitch and has editing the network scripts in the wrong order for me; I prefer that the bridge be configured and working before trying to install OpenStack.

This post does not cover a high-availablity installation, it is for a simple home lab where having a single network/control node is adequate and you have a few servers lying around with enough resources to be additional compute nodes (whether physical or with capacity to run KVM servers to be compute nodes).

While the post covers adding additional compute nodes it you wish to use the ‘allinone’ environment simply omit adding additional ip-addresses to the list of compute nodes when editing the answers file.

The last release of OpenStack from the RDO project for CentOS7 is the “Train” release. To obtain the latest “Ussuri” release you must be running CentOS8. This post covers using CentOS8 as we all want the latest release of course; I used CentOS8 media for 8.0.1905 installation.

If you follow all the steps in this post you will end uo with a working OpenStack environment with full external network connectivity

Creating the installation environment, changes needed on the network/controller server

Install two (2) or more new CentOS8 servers, I used KVM with the first server to be used as the network/control node with 15Gb memory and with a 70Gb disk, and a compute node and the second server a dedicated compute node with 10Gb memory with 50Gb disk. These servers must have static ip-addresses in your network range. I used 192.168.1.172 for the network/control node and 192.168.1.162 for the dedicated compute node. Memory allocations for dedicated compute nodes depend on what you intend to run of course. It is important to note these new servers should be assigned fully qualified hosts names.

Note: if you want more than one dedicated compute node create additional CentOS8 servers with static ip-addresses at this time also. However ensure you do not go mad and over-allocate compute nodes simply because you have spare capacity now; you may want to use that spare capacity for something else later and it is a lot harder to remove a compute node than to add an additional one so only define those you need initially, and add more later if needed in preference to trying to unconfigure unused compute nodes later on.

It should also be noted that CentOS8 does not provide the network-scripts package by default as it is depreciated. However it is a requirement that this is used rather than NetworkManager to configure your static-ip setup; as the scripts will need to be edited to setup bridging (on the assumption you want network access for your openstack environment).
eithert
A note on disk sizing. 50Gb of virtual disk size should be more than enough for both servers if you do not intend to create permanent volumes or create snapshots, however if you do wish to do either of those it is important to note that by default SWIFT storage is on a loopback device on your filesystem. The maximum size of this can be set when editing the answers file discussed later in this post but you need to reserve enough space on your network/control node to cope with all the persistant storage you are likely to use.

I should also point out at this time that I place a compute node on the network/control node spcifically to run a single small ‘gateway’ server instance as a bridge between the openstack private network and my normal external network (as if the network/control server is down there is no point havingh it anywhere else and placing it there eliminates network issues in reaching it) after which I disable the hypervisor for the network/control node to force all new instance creations to only be created on dedicated compute nodes. You may wish to not place any compute node functions on your network/control node which is probably the recomended method.

Once the new servers have been created you must update the /etc/hosts files on all the new servers (or dns servers if you use those) to ensure they are able to resolve each other by fully qualified server names, if they are not able to resolve each other installation will fail half way through leaving a large mess to clean up, to the point it is easier to start again from scratch, so ensore they can resolve each other. Also at this time on all servers perform the below steps.

dnf install network-scripts -y
systemctl disable firewalld
systemctl stop firewalld
systemctl disable NetworkManager
systemctl stop NetworkManager
systemctl enable network
systemctl start network

I prefer using OVS as the backend for the network node rather than the default of OVN, however I was unable to get this release of OpenStack networking working using OVS so this post covers installing it to use OVN which is fine for small home labs but does not support the VPNaaS or FWaaS services and uses Geneve as the encapsulation method for tenant networks.

OpenVswitch should be installed and configured before trying to install OpenStack to ensure the bridge is working correctly.

With all the notes above, only on the network/controller node perform the following steps

dnf update -y
dnf config-manager --enable PowerTools
dnf install -y centos-release-openstack-ussuri
dnf update -y
dnf install -y openvswitch
systemctl enable openvswitch

Then you need to edit some files in /etc/sysconfig/network-scripts, the initial filename will change based on your installation but for this example we will use mine which is ifcfg-ens3. Copy (not mode, copy) the file to ifcfg-br-ex ( ‘cp -p ifcfg-ens3 ifcfg-br-ex’ ); then edit the ifcfg-br-ex file to have the following changes.

  • The TYPE becomes TYPE=”OVSBridge”
  • The DEVICE becomes DEVICE=”br-ex”
  • The NAME becomes NAME=”br-ex”
  • Change BOOTPROTO from none to BOOTPROTO=”static”
  • Add a line DEVICETYPE=ovs
  • Add a line USERCTL=yes
  • Add a line DOMAIN=”xxx.xxx.xxx” where your domain is used, for example if your servername is myserver.mydept.example.com use mydept.example.com here
  • Delete the UUID line, that belongs to ens3 not br-ex
  • If a HWADDR line exists delete that also as it also referes to ens3 (a fresh install of CentOS8 does not use HWADDR)
  • All remaining parameters (ipaddr, dns, gateway etc remain unchanged)

Now you need to edit the origional ifgfg-xxx file, in my case edit ifcfg-ens3. This is an exercise in deletion, with only a few edits other than deleting lines, so it is easier to show an example. The below is what the ifcfg-ens3 file looks like after editing. Note that the HWADDR can be obtained from the ‘ether’ field of an ‘ifconfig ens3’ display and the UUID value will have been populated in the origional file during the install (either UUID or HWADDR can be used but I prefer to code both).

DEVICE="ens3"
BOOTPROTO="none"
TYPE="OVSPort"
OVS_BRIDGE="br-ex"
ONBOOT="yes"
DEVICETYPE=ovs
HWADDR=52:54:00:38:EF:48
UUID="6e63b414-3c7c-47f2-b57c-5e29ff3038cd"

The result of these changes is that the server ip-address is going to be moved from the network interface itself to the bridge device br-ex and managed by openvswitch after the server is rebooted.

One final step, update /etc/hostname to contain the fully qualified name of your server.

Then reboot the network/controller node. When it restarts ‘ifconfig -a’ (or ‘ip a’) must show that the ip-address has been moved to the new br-ex device.

If all has gone well the server is configured correctly for the install to begin on this server once the compute nodes have been prepared.

Creating the installation environment, changes needed on the compute nodes servers

After all the work above you will be pleased to see there is very little effort required here. Simply perform the steps below on every compute node to ensure that when the deployment needs packages installed the repositories needed are configured. Also ensure you followed the steps for all servers to switch from using NetworkManager to network and disable firewalld as was mentioned earlier.

dnf update -y
dnf config-manager --enable PowerTools
dnf install -y centos-release-openstack-ussuri
dnf update -y

Also update /etc/hostname to ensure it is set to the correct FQDN for the server, and remember to ensure the /etc/hosts file (or dns servers) have been updated to be able to resolve every nee server you have created for this envoronment.

Backup all your Virtual machine disks

At this stage you have a environment ready to install the RDO packaging of OpenStack onto.

You would not want to have to repeat all the steps again so shutdown the VMs and backup the virtual disk images. This will allow you to restart from this point as needed.

Once the virtual disk images have been backed up restart the VMs and continue.

Preparing the installation configuration settings, on the control node

Packstack by default will build a stand-alone single all-in-one environment with the optional features it thinks you may need. We wish to override this to support our additional compute nodes and add any other optional features you may wish to play with.

To achieve this rather than simply running packstack with the ‘–allinone’ option we will use the option ‘–gen-answer-file=filename’ packstack option to generate an answers file that we can edit to suit the desired configuration and feature installs.

Note the br-ex mapping to ens3 which was my interface, change ens3 to your interface name. Also note that as mentioned above we are using OVN networking.

dnf install -y openstack-packstack
packstack --allinone --provision-demo=n \
   --os-neutron-ovn-bridge-mappings=extnet:br-ex \
   --os-neutron-ovn-bridge-interfaces=br-ex:ens3 \
   --gen-answer-file=answers.txt \
   --default-password=password

In the example above the answers file is written to answers.txt; we need to edit this file to customise for the environment we wish to build.

You must search for the entry CONFIG_COMPUTE_HOSTS and update the entry with a comma seperated list of all the compute node server ip-addresses you wish to become compute nodes. In my case as the default is 192.168.1.172 (the network/control node packstack was run on) I just added the second ip-address also.

Other entries to note are the entries CONFIG_CINDER_VOLUMES_SIZE which defaults to 20G and CONFIG_SWIFT_STORAGE_SIZE which defaults to 2G. This amount of space will be needed to be available on your virtual disk filesystem. The first CONFIG_CINDER_STORAGE used space under /var/lib/cinder and must be large enough to contain all the block storage devices (disks) for all instances you will launch so if you will be running instances with large disks you will probably want to increase that. The second is for a loopback filesystem for swift object storage and I have had no problems with leaving that at 2G. Note however I do not use snapshots and seldom create additional volumes for instances, if you intend to do so definately increase the value of the first, as I am using a virtual disk size of 70G on the network/contro,l node and 50G on the compute nodes I set both to 20G for my use.

As a general rule options in the file set to “y” should be left that way but the other options in the file you can change from “n” to “y” to suit your needs, for example I use heat patterns so set CONFIG_HEAT_INSTALL=y (and CONFIG_HEAT_DB_PW, CONFIG_HEAT_KS_PW, CONFIG_HEAT_DOMAIN_PASSWORD, CONFIG_MAGNUM_DB_PW, CONFIG_MAGNUM_KS_PW set), likewise I set CONFIG_MAGNUM_INSTALL=y for container infrastructure support.

Setting entries turned on by default to “n” cannot be guaranteed to have been tested but will generally work.

This will run KVMs ‘hot’ (lm-sensors shows my kvm host cpu temperatures go from 35 to 85 (with 80 being the warning level on my cores)) so I did for my use set CONFIG_CEILOMETER_INSTALL and CONFIG_AODH_INSTALL to “n” as I don’t need performance metrics, and that alone dropped the temperatore of the cores by 10 degrees.

Interestingly when I gave up on OVS networking and switched to OVN networking temperatures dropped another 10degrees so OVN networking is preferred. But expect a lot of spinning cooling fan noise anyway.

When you have customised the answers file to suit your needs you are ready to perform the install.

Performing the OpenStack install

You have done all the hard work now, to install OpenStack simply run packstack using the answers file ensuring all your new servers can resolve ip-addresses to hostnames via /etc/hosts or DNS and that all the servers are available, you may want to ssh from the network/control node to each of the compute node servers to ensure connectivity before running the packstack command, and recheck name resolution.

Remember that the commands I have used are for an openswitch OVN environment so ensure you performed the steps to create the br-ex bridge covered earlier also.

To perform the instal simply run packstack using your customised answers file as below. You will be prompted to enter the root password for each of the compute you have configured. You may need to use the –timeout option if you have a slow network; not just a slow internal network but internet as well as many packages will be downloaded. It will probably take well over an hour to install.

packstack --answer-file=answers.txt [--timeout=600000]

When it states the installation has been sucessful define a router using a flat network to your local network, then create a floating ip range that can be used by openstack, ensure the floating ip range is not used by any of your existing devices.

Note that to issue any commands you need to source the keystonerc_admin file that will have been created in the root users home directory to load credentials needed to issue configuration commands.

These commands can be enteres as soon as the ‘packstack’ command has completed sucessfully as it starts all the services required as part of the installation. Change the network addresses to the addresses used by your external network and ensure the allocation pool range does not conflict with any addresses published by your dhcp server or home router).

source keystonerc_admin
neutron net-create external_network \
  --provider:network_type flat \
  --provider:physical_network extnet \
  --router:external
neutron subnet-create --name public_subnet \
  --enable_dhcp=False \
  --allocation-pool=start=192.168.1.240,end=192.168.1.250 \
  --gateway=192.168.1.1 external_network 192.168.1.0/24

Once this step has completed ‘tenant’ private networks can be created and configured to use the router for external network access, and floating up-addresses can be assigned to servers within the tenant private network to allow servers on the external network to connect to servers on the private network. What I would normally do is start only one instance with a floating ip-address per private network and simply add a route to my desktop to access the private network via that gateway (ie: if the gateway was assigned floating ip 192.168.1.243 and the private network within the OpenStack tenant environment was 10.0.1.0/24 I would simply “route add -net 10.0.1.0/24 gw 192.168.1.243” and be able to ssh directly to any other instances in the 10.0.1.0/24 network via that route).

If you have reviewed the documentation on the RDO website you will have seen that a project is created and a user assigned to the project, router and tenant private network created from the command line interface. I personally prefer doing that through the horizon dashboard after installation to ensure everything looks like it is working correctly; to do so logon as admin and create a project, then create a personal user user and assign it to that project in an admin role.

To access the horizon interface simply point your webbrowser at “http://the address of your controller node/dashboard”.

After creating the project and user logoff the dashboard and logon again as the new user.

  • Go to Network/Networks and create a new private network for your project, example marks_10_1_1_0, subnet marks_10_0_1_0_subnet1 with 10.0.1.0/24 (let gateway default), subnet details would be 10.0.1.5,10.0.1.250 (do not use the first few entries as they used to be reserved, ie: 10.0.1.1 used to be assigned to the gateway so do not permit it in the allocation pool)
  • Then create a router for your project using Network/Routers for example marks_project_router and assign it to the predefined ‘external_interface’ we created from the command line earlier; then from the router list select the new router and the interfaces tab and from there attach your projects private network to the router also. Instances in your project will now have external connectivity and be able to be assigned a loating ip-address from the public_network allocation range defined from the command line earlier when the public subnet was created
  • This would also be a good time to use Network/Security Groups to create a security group to use for testing such as a group named allow_all, a new group defaults to allow all for egress but we want to also add rules ingress tcpv4 ALLTCP, ingress ALLICMP (to allow ping) and egress ALLICMP so we can test connectivity to everything and also use tools like ping for troubleshooting. Obviously when you are happy an isntance is working you would want to create custom security group rules only permitting the access required but rules can be added/deleted on the fly and multiple groups can be used so a server may contain for example a rule for http and mariadb rather than needing a combined rule with both
  • before logging out and still as your own userid go to Project/Compute/Key Pairs and create a ssh key for your userid, you will need it to ssh into instances you launch

At this time you would also want to create a ‘rc’ file for your new user, ‘cp -p keystonerc_admin keystonerc_username’ end edit the new file to contain your new username and password and set the project to your personal project; this is the rc file you will source when working from the command line for your project instead of using the admin project.

This is a good time to look around, from your project signon look at Admin/Compute/Flavors (if you remembered to make your personal userid an admin role); you will see that the default flavors are too large for most home lab use, you will use this location to define custom flavours useful to your environment as you load images to use for your servers. You wil also notice that under the Images selection there are no images available which is correct, we have not yet adeded any.

Also check the Hypervisors tab to make sure all the compute nodes you defined in the answers file have been correctly setup. Testing the compute nodes is covered later in this post.

Obtaining cloud images to use

To launch an instance you need a cloud image and a flavour that supports the image. Fortunately many distributions provide cloud images that can be used in OpenStack, for example the Fedora33 one can be found at https://alt.fedoraproject.org/cloud/. There are also CentOS cloud images available at https://cloud.centos.org/centos/8/.

It is important to note that not all operating systems provide cloud images, and some operating systems simply will not run in an OpenStack environment; an example of one such is OpenIndianna which runs fine in a KVM but will not run properly under OpenStack.

Once you have a cloud image downloaded onto your network/control node you need to load it into OpenStack, to do so you need to define a few minimum values needed for the image. Using the F33 image as an example the cloud image disk size can be obtained from qemu-img as below.

[root@vmhost3 Downloads]# qemu-img info Fedora-Cloud-Base-33-1.2.x86_64.qcow2
image: Fedora-Cloud-Base-33-1.2.x86_64.qcow2
file format: qcow2
virtual size: 4 GiB (4294967296 bytes)
disk size: 270 MiB
cluster_size: 65536
Format specific information:
    compat: 0.10
    refcount bits: 16
[root@vmhost3 Downloads]#

That shows the minimum virtual disk size that can be allocated is 4Gb, it is important to do this step as disk sizes change, for example CentOS7 cloud image needs a minimum of a 10G virtual disk. It is up to you to decide what the miminum memory requirements should be, to load the F33 image you would use commands such as the below (making it public allows all tenants to use it, if omitted only the project owner can use it; you would create a keystomerc_username for each of your own project/user environments if you wanted the image private to your own environment).

source keystonerc_admin     # note you can use your own projects rc file here
glance image-create \
 --name "Fedora33" \
 --visibility public \
 --disk-format qcow2 \
 --min-ram 512 \
 --min-disk 4 \
 --container-format bare \
 --protected False \
 --progress \
 --file Fedora-Cloud-Base-33-1.2.x86_64.qcow2

Once the image is loaded you would use the horizon dashboard to create a new flavour that supports the new image; rather than use the default flavours which will be too large. The minimum disk size is important and you must code it to avoid issues; while you could load the image with no min-disk-size if you then tried to launch an instance with this disk with a 2Gb disk size flavor it would obviously crash.

Also note that the cloud-init scripts will resize the image upward automatically if a larger disk size is used in a flavor so you can load the image with a min-disk of 4 and use a flavor with a disk size of 10G quite happily and end up with a 10G disk in your instance.

You should load all the openStack cloud images you are likely to need to use at this time, I would generally have a few versions of Fedora and CentOS. Create flavors for the images also.

Testing your installation

If you had a look around the dashboard as suggested earlier you will have found the hypervisors display, from the compute nodes tab of that screen you are able to individually disable compute nodes.

What you should do as a final verification step is disable all but one compute node at a time an launch an instance with a security group rule that allows ICMP so you can ping it to ensure the instance starts correctly on each individually active compute node and that you have console connectivity to the instance via the daskboard instances screen. Some earlier releases required manual correction of configuration files on compute nodes to obtain console access but that has been fixed in this release, but still needs to be tested.

From the instances screen you can select each instance and the details will show you which compute node an instance has been configured on.

You should assign a floating ip-address to one of the instances and ensure you can ssh into the instance on the floating ip-address assigned using the key-pair you created. Note that the userid to use for each instance differes, for Fedora cloud images the user will be fedora, likewise use the userid centos for CentOS cloud images. That will verify inward connectivity. Use syntax suxh as “ssh -i identity_file.pem fedora@floating-ip-address”.

From that ssh session to your server you should also from that instance connection ping the instances you started on other compute nodes to test private network connectivity; you cannot ssh into them unless you copy your key to the instance you just logged onto. Note that if in the user configuration section when you launched your instance you set the root password you could logon directly from a console session to do the ping tests.

You should also ping one of the servers in your external network to ensure outward connectivity, and an internet based server also to ensure routing to the big wide world works as you will probably want to be installing software from repositories onto your instances.

Once you are happy all compute nodes are working correctly you can re-enable all the compute nodes; delete your test instances and start using it.

Additional Tips and notes

  • The Fedora33 image load example used in this post had a minimum memory allocation of 512; dnf will be killed by the early out-of-memory killer with this allocation but then run OK with over 100K free, if you want to use dnf allocate at least 756 in your flavour
  • In the user custom script section always have the first line as “#!/bin/bash” or commands will not be executed but produce an invalid multipart/mime error from cloud-init; to enable easy troubleshooting I normally have in that section
    #!/bin/bash
    echo "password" | passwd root --stdin
    
  • you do not need many floating ip-addresses, for each private network I only assign one to a server and use that server as a gateway/router into the private network from my external network
  • I recomend installing heat, using heat patterns to deploy a stack of servers is the easiest way to do so; some of my earlier posts have examples of using heat patterns to deploy multiserver test environments
  • remember to make your personal userid an admin role; this avoids having to repeatedly login as admin to enable/disable hypervisors and manage flavors
  • Also note that if you have a slow network between compute nodes the first instance deployment for an image may fail, as the image must be copied to the remote compute node before the instance launches and may timeout. Waiting for 5-10mins and trying again will work as the image will have completed transferring and not need to be copied again; although unused images will be cleaned up by timers if it remains unused on the compute node for too long
Posted in OpenStack, Virtual Machines | Comments Off on Installing OpenStack Ussuri in a multicompute node configuration in your home lab

DropBox and its LanSync facility

First let me make it clear this post is on dropbox as used in a Linux environment, specifically for this post Fedora (Fedora 32). Dropbax clients may behave differently in different environments.

What is lansync

The dropbox reference pages promote lansync as a way of saving external bandwidth, in that if a file is updated it can be replicated to other machines replicating that folder across the local subnet/network without each local client needing to retrieve the changed file from the dropbox servers.

Ports lansync and dropbox use

A DuckDuckGo search of “dropbox lansync port numbers” returns the following pages.
The description of lansync is that it wants port 17500 on both udp and tcp.
(reference https://help.dropbox.com/installs-integrations/sync-uploads/lan-sync-overview)
Or 17500 only on tcp (reference https://dropbox.tech/infrastructure/inside-lan-sync)

From observation it uses port 17500 on udp, tcp, and tcp6

[mark@hawk bin]$ netstat -an | grep 17500
[mark@hawk bin]$ dropbox lansync y
[mark@hawk bin]$ netstat -an | grep 17500
tcp        0      0 0.0.0.0:17500           0.0.0.0:*               LISTEN     
tcp6       0      0 :::17500                :::*                    LISTEN     
udp        0      0 0.0.0.0:17500           0.0.0.0:*                          

However, due to the extensive logging on run on one of my servers, a server which does not run dropbox, only udp appears to be used. Worse, dropbox never tops trying, two machines run dropbox and each are retying a server that will never respond at thirty second intervals

Sep 17 14:49:24 mdickinson kernel: DROPPED IN=ens3 OUT= MAC=ff:ff:ff:ff:ff:ff:50:b7:c3:20:19:8f:08:00 SRC=192.168.1.9 DST=255.255.255.255 LEN=161 TOS=0x00 PREC=0x00 TTL=64 ID=34187 DF PROTO=UDP SPT=17500 DPT=17500 LEN=141 
Sep 17 14:49:33 mdickinson kernel: DROPPED IN=ens3 OUT= MAC=ff:ff:ff:ff:ff:ff:74:d0:2b:92:f4:f7:08:00 SRC=192.168.1.187 DST=255.255.255.255 LEN=161 TOS=0x00 PREC=0x00 TTL=64 ID=7163 DF PROTO=UDP SPT=17500 DPT=17500 LEN=141 
Sep 17 14:49:54 mdickinson kernel: DROPPED IN=ens3 OUT= MAC=ff:ff:ff:ff:ff:ff:50:b7:c3:20:19:8f:08:00 SRC=192.168.1.9 DST=255.255.255.255 LEN=161 TOS=0x00 PREC=0x00 TTL=64 ID=54938 DF PROTO=UDP SPT=17500 DPT=17500 LEN=141 
Sep 17 14:50:03 mdickinson kernel: DROPPED IN=ens3 OUT= MAC=ff:ff:ff:ff:ff:ff:74:d0:2b:92:f4:f7:08:00 SRC=192.168.1.187 DST=255.255.255.255 LEN=161 TOS=0x00 PREC=0x00 TTL=64 ID=21945 DF PROTO=UDP SPT=17500 DPT=17500 LEN=141 
Sep 17 14:50:24 mdickinson kernel: DROPPED IN=ens3 OUT= MAC=ff:ff:ff:ff:ff:ff:50:b7:c3:20:19:8f:08:00 SRC=192.168.1.9 DST=255.255.255.255 LEN=161 TOS=0x00 PREC=0x00 TTL=64 ID=2628 DF PROTO=UDP SPT=17500 DPT=17500 LEN=141 
Sep 17 14:50:33 mdickinson kernel: DROPPED IN=ens3 OUT= MAC=ff:ff:ff:ff:ff:ff:74:d0:2b:92:f4:f7:08:00 SRC=192.168.1.187 DST=255.255.255.255 LEN=161 TOS=0x00 PREC=0x00 TTL=64 ID=26919 DF PROTO=UDP SPT=17500 DPT=17500 LEN=141 

Note: when dropbox is running it also uses ports 17600 and 17603, although these are bound to localhost so not a risk as long as you have those ports open for access from localhost (yes I do have some firewall rules that prevent access to services from localhost). That is documented at https://help.dropbox.com/installs-integrations/desktop/configuring-firewall

root@hawk ~]# netstat -an | grep 176
tcp        0      0 127.0.0.1:17600         0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:17603         0.0.0.0:*               LISTEN 

Nowhere can I find documentation on when and why dropbox will use port 17601/tcp. However on multiple occasions on multiple machines I have seen port 17601 tcp in use by /home/mark/.dropbox-dist/dropbox-lnx.x86_64-105.4.651/dropbox (identified by ‘netstat -anp’ and querying the pid; note also seen on earlier versions of dropbox), although only on localhost (only listening on 127.0.0.1). And it appears to stop listening immediately when lansync is turned off ?.

The same cannot be said for the udp port 17500, turning off lansync stops the 30 second polling but leaves the local udp port open until dropbox is restarted.

[mark@hawk bin]$ dropbox lansync n
[mark@hawk bin]$ netstat -an | grep 17500
udp        0      0 0.0.0.0:17500           0.0.0.0:*                          
[mark@hawk bin]$ dropbox stop
Dropbox daemon stopped.
[mark@hawk bin]$ dropbox start
[mark@hawk bin]$ netstat -an | grep 17500
[mark@hawk bin]$ dropbox status
Up to date
[mark@hawk bin]$ 

It is probable that it uses udp to find machines, and tcp to transfer data.

Why not to use lansync, and when it may be ok

In a small replication environment where there may be only two or three machines replicating a folder if the file changes are small it is probably going to generate less network traffic by having all machines use the dropbox servers as the source for the changed file; especially as whichever machine changes the file will push it to the dropbox servers anyway.

Also in a small replication environment where there may be only a few users replicating the directory contents having those few users running lansync to poll every machine in the local subnet every thirty seconds is a large overhead (there may be hundreds of machines on the local subnet having to put up with all the polling).

Then of course there may be other small groups all doing the same thing causing a lot of needless broadcast udp traffic.

In environments such as this the preferred solution would be to do something like have an ownCloud or nextCloud server for each small group, all that needs is a single http server and each group could be assigned its own unique url to their own copy of it. Yes both of those two file sync software products also have clients that perform extensive polling, but only to the ownCloud/nextCloud server they are configured to use if they are doing file syncronisation rather than to every server and desktop in the local subnet/network. And if the files should be on dropbox, that one server can push them there; with maybe one ‘manager’ interacting with dropbox to manage conflicts.

In a large environment lansync would make sense if the majority of users on the same subnet were all interesting in replicating the same set of files. However I would think such a situation would be the exception rather than the norm.

It would also make sense in an environment where internet bandwidth is constrained or chargeable as while generating a lot of additional traffic on the local subnet it should cut down on external internet traffic, although one copy would always be uodated on the dropbox servers.

The main issue with lansync

The main issue with lansync is that is enabled by default. For home users with a small local network of a few PCs, maybe a TV, possible a couple of cell phones and maybe a laptop or tablet, connected to your default home router; having all those devices spammed with UDP traffic every thirty seconds simply because one device may have had dropbox installed on it is a pretty bad default.

In a large commercial environment even where lansync may make sense having it spam from install time before admins get around to setting up routing/firewalls/filtering also seems like a bad default; it should default to off in both large and small environments and turned on if needed.

However as toggling it is as sinple as using the commands ‘dropbox lansync n’ and ‘dropbox lansync y’ it is only an issue if users do not know that is is enabled by default. I only discovered it was the default when the firewall logs on one of my servers starting dropping traffic on port 17500 and I investigated where it was coming from.

Disclaimer

I do use dropbox for personal use, there are some files I want to guarantee a copy of should all my servers suddenly die, as it is only on a desktop and laptop (laptop normally powered off) I have disabled lansync.

A second desktop is just manually kept in sync by copying changes to important files in the dropbox folder to an ownCloud folder syncing across all my desktop machines; and of course bacula does daily backups of both.

For important files do not rely on one solution. An if you are syncronising files across multiple desktops use a solution that does not broadcast udp traffic to servers, TVs, cell phones etc as that is a needless overhead that you do not want; if you use dropbox at home disable lansync.

Posted in Unix | Comments Off on DropBox and its LanSync facility