Migrating Gitea from Docker to Kubernetes
I deployed Gitea initially using docker compose to just get it up and running. As things progressed on my team, we migrated most of our core services to k8s. Gitea was one of those core services. You’d think just a simple app backup/restore, except that Gitea has no real ‘restore’ functionality.
I’m going to assume a couple of things for the sake of keeping this brief.
- You’re migrating to/from the same version of Gitea and same database backend (in this case, I’m going to be using Postgres). I originally wasn’t but doing an upgrade on your Docker installation solves this problem.
- You have successfully deployed Gitea to your k8s cluster using their helm chart
- you gitea pod is called
- your postgres pod is called
- you’ve deployed into the
- you gitea pod is called
- You have a Docker-based installation:
- Your Gitea container is called
/datain the container bind-mounted to
/opt/dockervol/gitea/gitea-dataon the host*
- Your Postgres database container is called
/var/lib/postgresql/datain the container bind-mounted to
/opt/dockervol/gitea/postgreson the docker host*
- Your Gitea container is called
* You can accomplish these tasks without the bind mounts. Instead of copying the tarballs/dumps directly off the docker host filesystem, you’ll have to do a
docker cpto get them out of the container first. From there, copy them to where you can work with them and k8s (specifically where you can execute
Deploy gitea with the helm chart
I deployed the helm chart with relatively default values. I’m not going to go through the whole process here. One thing I did do (relevant to this migration) is upgrade the
bitnami/postgres container to a later version so I had a better chance at the database import. In my
values.yaml for the
postgresql: enabled: true ... image: tag: 12-debian-10 ...
On the docker host:
# enter the container docker exec -it gitea_db /bin/bash
And then, in the container
# dump the db pg_dump gitea -U gitea > /var/lib/postgresql/data/gitea_manual_dump.sql
Get that dump file off of the docker host and to somewhere where you can run
kubectl on your new cluster.
Before we do any work with the database on k8s, we need to stop Gitea so it doesn’t write while we’re pulling our Peter Venkman tablecloth trick. Scale down the
kubectl scale statefulset gitea --replicas 0
Then copy the file in to the Postgres container and then get a shell on it:
kubectl cp gitea_manual_dump.sql gitea-postgres-0:/tmp/. -n gitea kubectl exec -it gitea-postgresql-0 -- /bin/bash
Once in the container, drop the current database, create a new one, and import your dump. You’ll need the gitea postgres password you deployed the helm chart with.
psql template1 -c 'drop database gitea;' -U gitea psql template1 -c 'create database gitea with owner gitea; -U gitea exit
StatefulSet back up to
1 to start the pod again
kubectl scale statefulset gitea --replicas 1
And thats it! Well, for the database. Now on to the gitea repos and associated data.
So here things aren’t as cut/dry. Your best bet is to look at your docker gitea config (stored typically in
/data/gitea/conf/app.ini in the docker install) and see whats getting referenced.
The things I found I needed to pay attention to were:
[repository] ROOT = /data/git/repositories [repository.local] LOCAL_COPY_PATH = /data/gitea/tmp/local-repo [repository.upload] TEMP_PATH = /data/gitea/uploads [picture] AVATAR_UPLOAD_PATH = /data/gitea/avatars REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars DISABLE_GRAVATAR = false ENABLE_FEDERATED_AVATAR = true [attachment] PATH = /data/gitea/attachments
For each of these sections, look at the paths and see if theres any data in them (say, for example,
/data/gitea/avatars). Make note of those dirs (and their settings), you may need to add some configuration stanzas to your k8s config.
In general, just tar up the whole
/data dir (or
/opt/dockervol/gitea/gitea-data on your docker host), and get it to a host where you can kubectl with:
tar cvfz gitea-data.tgz /opt/dockervol/gitea/gitea-data
Copy it into the container (just like we did with Postgres), and get your self a shell on that pod in k8s
kubectl cp gitea-data.tgz gitea-0:/tmp/. -n gitea kubectl exec -it gitea-0 -- /bin/bash
Once in the pod, extract that directory and start migrating data over. In my installation, I was going from Gitea 1.14.x in docker to 1.15.x in k8s. For some reason, in the docker container, my folder structure looks like this:
# tree -L 2 /data ├── git │ ├── lfs │ └── repositories ├── gitea │ ├── attachments │ ├── avatars │ ├── conf │ ├── indexers │ ├── jwt │ ├── log │ ├── queues │ ├── repo-archive │ ├── repo-avatars │ └── sessions ...
And in the k8s
gitea-0 pod, it looked like this:
# tree /data -L 2 /data ├── attachments ├── avatars ├── git │ └── gitea-repositories ├── gitea │ ├── conf │ └── log ├── indexers │ └── issues.bleve ├── jwt │ └── private.pem ├── lfs ├── lost+found ├── queues │ └── common ├── repo-archive ├── repo-avatars ...
Why the moved some of the directories, who knows. The main point is that if a section (say, for example
[repositories]) was pointing at
/data/git/repositories in my docker install, I copy that folder out of the data tarball currently in
/tmp in the container and put it wherever the gitea installation on k8s expects it. In my case the k8s instance was expecting it in
Additionally, you may need to add stanzas to your k8s config. I had to add my
[pictures] stanza so that the
Repository avatars werent missing. These are stored on the filesystem whereas the user ones are stored in the database (as far as I can tell):
[picture] AVATAR_UPLOAD_PATH = /data/gitea/avatars DISABLE_GRAVATAR = false ENABLE_FEDERATED_AVATAR = true
Once you think you’ve migrated all your changes, exit the pod and delete it so it gets re-created by the
kubectl delete pod gitea-0 -n gitea
Once the pod comes back up, navigate to the website and poke around, try to create issues, push to the repo, etc. If you don’t get any
500 errors, you’re good to go!
Additional things I did for good measure (though not sure if I needed them):
- ran the re-generate hooks script specified at the end of the backup/restore docs on my k8s install:
./gitea admin regenerate hooks
- ensure everything under my repository directory (
gitea-0container) was owned by
git(user and group)
It’s not an immediately obvious transition, but well worth the time. If you have any questions, or find any issues with this tutorial, reach out!
All product and company names are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.