Migrating subversion and git to k8s

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.

Docker image

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.

Apache configuration

Next step is the configuration file of the apache server that I will discuss in parts.

Health check

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.

Logging

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

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.

Git

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.

Apache StatefulSet

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.

Final thoughts

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.

This entry was posted in Devops/Linux. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *