{"id":2448,"date":"2022-10-27T19:39:32","date_gmt":"2022-10-27T19:39:32","guid":{"rendered":"https:\/\/brakkee.org\/site\/?p=2448"},"modified":"2022-11-16T16:31:18","modified_gmt":"2022-11-16T16:31:18","slug":"migrating-subversion-and-git-to-k8s","status":"publish","type":"post","link":"https:\/\/brakkee.org\/site\/2022\/10\/27\/migrating-subversion-and-git-to-k8s\/","title":{"rendered":"Migrating subversion and git to k8s"},"content":{"rendered":"<p>The migration of my old VM based infrastructure at home to k8s is almost finished. The final steps to do are:<\/p>\n<ul>\n<li>moving version control to kubernetes: subversion and git<\/li>\n<li>moving my file shares\/NAS server<\/li>\n<li>hosting my DLNA server for playing movies from my server on my TV<\/li>\n<\/ul>\n<p>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.<\/p>\n<p><!--more--><\/p>\n<p>Therefore we can drop right in with the apache configuration. One problem I encounted was that extending <a href=\"https:\/\/hub.docker.com\/_\/httpd\">the official apache docker images<\/a> 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.<\/p>\n<h2>Docker image<\/h2>\n<p>The Dockerfile for this image is follows:<\/p>\n<pre>FROM rockylinux:9.0.20220720\r\nRUN yum makecache\r\nRUN yum install httpd mod_dav_svn svn git gitweb -y\r\nCMD \/usr\/sbin\/httpd -DFOREGROUND\r\n<\/pre>\n<p>The above file speaks for itself: take a base image and install the required plugins to make it work.<\/p>\n<h2>Apache configuration<\/h2>\n<p>Next step is the configuration file of the apache server that I will discuss in parts.<\/p>\n<h3>Health check<\/h3>\n<p>First part is the configuration required for the apache health check:<\/p>\n<pre>&lt;VirtualHost *:80&gt;\r\n  ServerName localhost\r\n  &lt;Location \/healthz&gt;\r\n    SetHandler server-status\r\n    &lt;RequireAny&gt;\r\n      Require ip 192.168.0.0\/16\r\n      Require ip 172.16.0.0\/12\r\n      Require ip 10.0.0.0\/8\r\n    &lt;\/RequireAny&gt;\r\n  &lt;\/Location&gt;\r\n&lt;\/VirtualHost&gt;\r\n<\/pre>\n<p>This allows the healt check on \/healtz defined in the pod configuration to work. It also allows the health check only from local networks.<\/p>\n<h3>Logging<\/h3>\n<p>The following commands add logging to stdout and errors to stderr in addition to logging to <em>\/var\/log\/httpd\/access_log<\/em> and <em>\/var\/log\/httpd\/error_log<\/em> respectively.<\/p>\n<pre>CustomLog \/proc\/self\/fd\/1 common\r\nErrorLog \/proc\/self\/fd\/2\r\n<\/pre>\n<h3>Subversion<\/h3>\n<p>Subversion is configured as follows:<\/p>\n<pre>&lt;Location \/svn&gt;\r\n   DAV svn\r\n   SVNParentPath \/data\/subversion\/\r\n\r\n   # no path authorization to improve speed\r\n   SVNPathAuthz off\r\n\r\n   AuthzSVNAccessFile \/etc\/httpd\/vcs\/subversion.auth\r\n   Satisfy Any\r\n\r\n   AuthType Basic\r\n   AuthName \"Public Subversion Repositories on example.com\"\r\n   AuthUserFile \/etc\/httpd\/vcs\/subversion.passwd\r\n   Require valid-user\r\n\r\n   SetInputFilter DEFLATE\r\n   SetOutputFilter DEFLATE\r\n   Header append Vary User-Agent env=!dont-vary\r\n&lt;\/Location&gt;\r\n<\/pre>\n<p>The subversion.auth file describes the access rights for different users to the repositories that are in subdirectories of \/data\/subversion. For example:<\/p>\n<pre>[groups]\r\nexamplegroup=erik, anotheruser\r\n\r\n[examplesvn:\/]\r\n@examplegroup = rw\r\n* = r\r\n<\/pre>\n<p>The above defines a group <em>examplegroup<\/em> consisting of the users <em>erik<\/em> and <em>anotheruser<\/em>. Then the users in this group are given access to the <em>examplesvn<\/em> 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 <em>r = *<\/em> line. See also the <a href=\"https:\/\/svnbook.red-bean.com\/en\/1.7\/svn.serverconfig.httpd.html\">documentation<\/a> that describes all possibilities.<\/p>\n<h3>Git<\/h3>\n<p>The git configuration of above, surprisingly, turns out to be fully identical to what I described years ago in <a href=\"https:\/\/brakkee.org\/site\/2011\/08\/06\/git-server-setup-on-linux-using-smart-http\/\">an older post<\/a> 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&#8217;t need the functionality. For true opensource projects I usually use github and push changes to both my local repo and to github.<\/p>\n<p>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:<\/p>\n<pre>git init --bare \r\n# extra checks\r\ngit config receive.fsckObjects true\r\n# force merges on local machine\r\ngit config receive.denyNonFastforwards true\r\n# deleting history requires special actions not allowed from a client\r\ngit config receive.denyDeletes true\r\n<\/pre>\n<p>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.<\/p>\n<h2>Apache StatefulSet<\/h2>\n<p>I chose to use a <em>StatefulSet<\/em> for apache to avoid concurrent access to the same data directories for subversion and git. It is probably also possible to use a <em>Deployment<\/em> instead, but a <em>StatefulSet<\/em> is a bit safer and there are no urgent high availability issues that would mandate a replica count of more than 1.<\/p>\n<p>The <em>StatefulSet<\/em> is as follows:<\/p>\n<pre>apiVersion: apps\/v1\r\nkind: StatefulSet\r\nmetadata:\r\n  name: httpd-vcs\r\n  namespace: example-com\r\n  labels:\r\n    app: httpd\r\nspec:\r\n  serviceName: vcs\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: httpd-vcs\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: httpd-vcs\r\n    spec:\r\n      containers:\r\n        - name: httpd\r\n          image: example.org\/httpd:latest                 # A\r\n          ports: \r\n            - containerPort: 80\r\n          volumeMounts:\r\n            - name: httpd-vcs-conf                        # B\r\n              mountPath: \/etc\/httpd\/conf.d\/vcs.conf\r\n              subPath: vcs.conf\r\n            - name: httpd-vcs-conf                        # C \r\n              mountPath: \/etc\/gitweb.conf                 \r\n              subPath: gitweb_config.perl\r\n            - name: httpd-vcs-conf\r\n              mountPath: \/etc\/httpd\/conf.d\/gitweb.conf    # D\r\n              subPath: gitweb.conf                        \r\n            - name: vcs-passwd                            # E\r\n              mountPath: \/etc\/httpd\/vcs                  \r\n            - name: vcs-subversion\r\n              mountPath: \/data\/subversion\r\n            - name: vcs-git\r\n              mountPath: \/data\/git\r\n            - name: vcs-log\r\n              mountPath: \/var\/log\/httpd\r\n          startupProbe:\r\n            periodSeconds: 1\r\n            httpGet:\r\n              port: 80\r\n              path: \/healthz\r\n              httpHeaders:\r\n                - name: Host\r\n                  value: localhost\r\n      volumes:\r\n        - name: httpd-vcs-conf\r\n          configMap:\r\n            name: httpd-vcs-conf\r\n        - name: vcs-passwd\r\n          secret:\r\n            secretName: vcs-passwd\r\n  volumeClaimTemplates:\r\n    - metadata:\r\n        name: vcs-subversion\r\n      spec:\r\n        volumeName: vcs-subversion\r\n        accessModes:\r\n          - ReadWriteOnce\r\n        resources:\r\n          requests:\r\n            storage: 10Gi\r\n    - metadata:\r\n        name: vcs-git\r\n      spec:\r\n        volumeName: vcs-git\r\n        accessModes:\r\n          - ReadWriteOnce\r\n        resources:\r\n          requests:\r\n            storage: 10Gi\r\n    - metadata:\r\n        name: vcs-log\r\n      spec:\r\n        volumeName: vcs-log\r\n        accessModes:\r\n          - ReadWriteOnce\r\n        resources:\r\n          requests:\r\n            storage: 10Gi\r\n<\/pre>\n<ul>\n<li><em># A<\/em>: The image built using the <em>Dockerfile<\/em> at the start of this post.<\/li>\n<li><em># B<\/em>: The apache config file mounted from a <em>ConfigMap<\/em><\/li>\n<li><em># C<\/em>: 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\n<pre>our $projectroot = \"\/data\/git\";\/pre&gt; here. Note that you must mount this file at \/etc\/gitweb.conf because mounting it next to the cgi script as mentioned in the <a href=\"https:\/\/git-scm.com\/docs\/gitweb.conf\">documentation<\/a> does not work.<\/pre>\n<\/li>\n<li><em># D<\/em>: Mount of a standard <em>gitweb.conf<\/em> file overriding the version from the RPM to use the correct URL:\n<pre>Alias \/gitweb \/var\/www\/git\r\n\r\n&lt;Directory \/var\/www\/git&gt;\r\n  Options +ExecCGI\r\n  AddHandler cgi-script .cgi\r\n  DirectoryIndex gitweb.cgi\r\n&lt;\/Directory&gt;\r\n<\/pre>\n<\/li>\n<li><em># E<\/em>: The required <em>subversion.auth<\/em>, <em>subversion.passwd<\/em>, and <em>git.passwd<\/em> files are mounted from a single <em>ConfigMap<\/em> in the <em>\/etc\/httpd\/vcs<\/em> directory.<\/li>\n<\/ul>\n<p>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.<\/p>\n<p>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.<\/p>\n<h2>Final thoughts<\/h2>\n<p>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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <a href=\"https:\/\/brakkee.org\/site\/2022\/10\/27\/migrating-subversion-and-git-to-k8s\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[10],"tags":[],"_links":{"self":[{"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/posts\/2448"}],"collection":[{"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/comments?post=2448"}],"version-history":[{"count":29,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/posts\/2448\/revisions"}],"predecessor-version":[{"id":2550,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/posts\/2448\/revisions\/2550"}],"wp:attachment":[{"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/media?parent=2448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/categories?post=2448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/tags?post=2448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}