The migration of my old VM based infrastructure at home to k8s is almost finished. The final steps to do are:
- moving version control to kubernetes: subversion and git
- moving my file shares/NAS server
- hosting my DLNA server for playing movies from my server on my TV
This post describes the first. There are of course many free alternatives for hosting version control, but nonetheless, I like to be in control completely and therefore I am also hosting my own subversion and git repositories. These are basically just Apache using a certain configuration.
Therefore we can drop right in with the apache configuration. One problem I encounted was that extending the official apache docker images by installing the required plugins for subversion and git was a bit problematic. Therefore, I decided to build my own apache HTTPD image based on rocky linux instead. I chose rocky because i am quite well versed with the whole RHEL/centos/rocky line of linux distributions and so I can do a lot in a short time.
The Dockerfile for this image is follows:
FROM rockylinux:9.0.20220720 RUN yum makecache RUN yum install httpd mod_dav_svn svn git gitweb -y CMD /usr/sbin/httpd -DFOREGROUND
The above file speaks for itself: take a base image and install the required plugins to make it work.
Next step is the configuration file of the apache server that I will discuss in parts.
First part is the configuration required for the apache health check:
<VirtualHost *:80> ServerName localhost <Location /healthz> SetHandler server-status <RequireAny> Require ip 192.168.0.0/16 Require ip 172.16.0.0/12 Require ip 10.0.0.0/8 </RequireAny> </Location> </VirtualHost>
This allows the healt check on /healtz defined in the pod configuration to work. It also allows the health check only from local networks.
The following commands add logging to stdout and errors to stderr in addition to logging to /var/log/httpd/access_log and /var/log/httpd/error_log respectively.
CustomLog /proc/self/fd/1 common ErrorLog /proc/self/fd/2
Subversion is configured as follows:
<Location /svn> DAV svn SVNParentPath /data/subversion/ # no path authorization to improve speed SVNPathAuthz off AuthzSVNAccessFile /etc/httpd/vcs/subversion.auth Satisfy Any AuthType Basic AuthName "Public Subversion Repositories on example.com" AuthUserFile /etc/httpd/vcs/subversion.passwd Require valid-user SetInputFilter DEFLATE SetOutputFilter DEFLATE Header append Vary User-Agent env=!dont-vary </Location>
The subversion.auth file describes the access rights for different users to the repositories that are in subdirectories of /data/subversion. For example:
[groups] examplegroup=erik, anotheruser [examplesvn:/] @examplegroup = rw * = r
The above defines a group examplegroup consisting of the users erik and anotheruser. Then the users in this group are given access to the examplesvn repository. In this case, it concerns a public repository so that all other users (including non-authenticated users) get read-only access. For a private repository, leave out the r = * line. See also the documentation that describes all possibilities.
The git configuration of above, surprisingly, turns out to be fully identical to what I described years ago in an older post and is therefore not repeated here. That post also describes the various alternatives and their pros and cons for setting up git. There are more complete setups for git using for instance gitlab but I chose not to do that since it is mostly a single user setup and don’t need the functionality. For true opensource projects I usually use github and push changes to both my local repo and to github.
One important addition not mentioned in the earlier post is the way to create new git repositories. This can be done from inside the vcs pod using the following commands:
git init --bare # extra checks git config receive.fsckObjects true # force merges on local machine git config receive.denyNonFastforwards true # deleting history requires special actions not allowed from a client git config receive.denyDeletes true
These settings make the setup more robust and also prevent server side merges that should be avoided. This puts the responsibility for the code fully with the user committing the files. Without this, a serverside merge could modify the code and then code would be checked out that was never actually used (or tested) by anyone. This is bad of course. Additionally, it is useful to prevent deletion of files.
I chose to use a StatefulSet for apache to avoid concurrent access to the same data directories for subversion and git. It is probably also possible to use a Deployment instead, but a StatefulSet is a bit safer and there are no urgent high availability issues that would mandate a replica count of more than 1.
The StatefulSet is as follows:
apiVersion: apps/v1 kind: StatefulSet metadata: name: httpd-vcs namespace: example-com labels: app: httpd spec: serviceName: vcs replicas: 1 selector: matchLabels: app: httpd-vcs template: metadata: labels: app: httpd-vcs spec: containers: - name: httpd image: example.org/httpd:latest # A ports: - containerPort: 80 volumeMounts: - name: httpd-vcs-conf # B mountPath: /etc/httpd/conf.d/vcs.conf subPath: vcs.conf - name: httpd-vcs-conf # C mountPath: /etc/gitweb.conf subPath: gitweb_config.perl - name: httpd-vcs-conf mountPath: /etc/httpd/conf.d/gitweb.conf # D subPath: gitweb.conf - name: vcs-passwd # E mountPath: /etc/httpd/vcs - name: vcs-subversion mountPath: /data/subversion - name: vcs-git mountPath: /data/git - name: vcs-log mountPath: /var/log/httpd startupProbe: periodSeconds: 1 httpGet: port: 80 path: /healthz httpHeaders: - name: Host value: localhost volumes: - name: httpd-vcs-conf configMap: name: httpd-vcs-conf - name: vcs-passwd secret: secretName: vcs-passwd volumeClaimTemplates: - metadata: name: vcs-subversion spec: volumeName: vcs-subversion accessModes: - ReadWriteOnce resources: requests: storage: 10Gi - metadata: name: vcs-git spec: volumeName: vcs-git accessModes: - ReadWriteOnce resources: requests: storage: 10Gi - metadata: name: vcs-log spec: volumeName: vcs-log accessModes: - ReadWriteOnce resources: requests: storage: 10Gi
- # A: The image built using the Dockerfile at the start of this post.
- # B: The apache config file mounted from a ConfigMap
- # C: The gitweb configuration file that provides a webinterface to git. This config file contains a file with only a modification to the setting of projectroot. I am using
our $projectroot = "/data/git";/pre> here. Note that you must mount this file at /etc/gitweb.conf because mounting it next to the cgi script as mentioned in the documentation does not work.
- # D: Mount of a standard gitweb.conf file overriding the version from the RPM to use the correct URL:
Alias /gitweb /var/www/git <Directory /var/www/git> Options +ExecCGI AddHandler cgi-script .cgi DirectoryIndex gitweb.cgi </Directory>
- # E: The required subversion.auth, subversion.passwd, and git.passwd files are mounted from a single ConfigMap in the /etc/httpd/vcs directory.
The other mounts are for the subversion and git data directories. Also a directory for apache log files is mounted. Files and directories for the volumes should be owned by user:group = 48:48.
Other configuration like creating a Service and exposing it through an ingress or other means are standard. Also creation of volumes is not shown. Network policies are applied as usual, only allowing access to subversion and git from the single pod that requires it and preventing egress traffic from the version control pod.
This has been a relatively straightforward post. The configuration for subversion and git I used was identical to what I configured 10 years ago. Sometimes, software is just finished and there is no need to change anything.