Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migration from CHT 3.x on docker-compose to CHT 4.x on k3s #1723

Merged
merged 18 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: "Migration from CHT 3.x to CHT 4.x in Kubernetes"
linkTitle: "K8s Data Migration to 4.x"
title: "Migration from CHT 3.x to CHT 4.x in EKS - Kubernetes"
linkTitle: "Migration: 3.x EKS to 4.x EKS"
weight: 1
description: >
Guide to migrate existing data from CHT 3.x to CHT 4.x in Kubernetes environments
Guide to migrate existing data from CHT 3.x on EKS to CHT 4.x on EKS (Kubernetes Environments)
relatedContent: >
---

Expand Down Expand Up @@ -150,10 +150,10 @@ Create a `values.yaml` file using the volume ID from the previous step:
For single node deployment, create a YAML file with this contents, being sure to update:

* `<your-namespace-defined-in-NAMESPACE>` (_two occurrences_)
* `<version>` - 4.x version you're upgrading too
* `<version>` - 4.x version you're upgrading to
* `<password>` - retrieved from `get-env` call above
* `<secret>` - retrieved from `get-env` call above
* `<admin_user>` - needs to be the same as used in 3.x - likely `medic`
* `<admin-user>` - needs to be the same as used in 3.x - likely `medic`
* `<uuid>` - retrieved from `get-env` call above
* `<size>` - Size of original 3.x EBS volume, eg `100Mi` for 100 Megabytes or `100Gi` for 100 Gigabytes (_two occurrences_)
* `<toleration-value>` - For production use `prod-couchdb-only`, for dev use `dev-couchdb-only`
Expand Down
2 changes: 1 addition & 1 deletion content/en/hosting/4.x/app-developer.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "App Developer Hosting in CHT 4.x"
linkTitle: "App Developer Hosting"
weight: 30
weight: 10
aliases:
- /apps/guides/hosting/4.x/app-developer
- /apps/guides/hosting/app-developer
Expand Down
6 changes: 6 additions & 0 deletions content/en/hosting/4.x/migration/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: Migration Guides
weight: 20
description: >
Guides for hosting, maintaining, and monitoring CHT applications
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
toc_hide: true
hide_summary: true
---

The hosting architecture differs entirely between CHT-Core 3.x and CHT-Core 4.x. When migrating from Docker Compose to K3s, specific steps are required using the [couchdb-migration](https://github.com/medic/couchdb-migration) tool. This tool interfaces with CouchDB to update shard maps and database metadata.

{{% alert title="Note" %}}
If after upgrading you get an error, `Cannot convert undefined or null to object` - please see [issue #8040](https://github.com/medic/cht-core/issues/8040) for a work around. This only affects CHT 4.0.0, 4.0.1, 4.1.0 and 4.1.1. It was fixed in CHT 4.2.0.
{{% /alert %}}


## Install Migration Tool
```shell
mkdir -p ~/couchdb-migration/
cd ~/couchdb-migration/
curl -s -o ./docker-compose.yml https://raw.githubusercontent.com/medic/couchdb-migration/main/docker-compose.yml
docker compose up
```

## Set Up Environment Variables

Be sure to replace both `<admin-user>` and `<password>` with your actual username and password. As well, update `<couchdb-host>` to the CouchDB URL from the Docker Compose setup:

```shell
export COUCH_URL=http://<admin-user>:<password>@<couchdb-host>:5984
```

## Run Pre-Migration Commands
```shell
cd ~/couchdb-migration/
docker compose run couch-migration pre-index-views <put-your-intended-cht-version>
```

{{% alert title="Note" %}}
If pre-indexing is omitted, 4.x API will fail to respond to requests until all views are indexed. For large databases, this could take many hours or days.
{{% /alert %}}

## Save CouchDB Configuration
```shell
cd ~/couchdb-migration/
docker compose run couch-migration get-env
```

Save the output containing:
- CouchDB secret (used for encrypting passwords and session tokens)
- CouchDB server UUID (used for replication checkpointing)
- CouchDB admin credentials

The next part of the guide assumes your K3s cluster is already prepared. If not, please run the set of commands [here](https://docs.k3s.io/quick-start).

We are also going to utilize the `cht-deploy` script from the [cht-core](https://github.com/medic/cht-core) repo. If you don't already have that, clone it.

## Prepare Node Storage

```shell
# Create directory on the node
sudo mkdir -p /srv/couchdb1/data

# Copy data from Docker Compose installation to the k3s node
sudo rsync -avz --progress --partial --partial-dir=/tmp/rsync-partial \
/srv/storage/medic-core/couchdb/data/ \
<user>@<node1-hostname>:/srv/couchdb1/data/
```
23 changes: 23 additions & 0 deletions content/en/hosting/4.x/migration/_partial_values_explanation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
toc_hide: true
hide_summary: true
---

Be sure to update the following values in your YAML file:

* `<your-namespace>` (_two occurrences_)
* `<version>` - 4.x version you're upgrading to
* `<password>` - retrieved from `get-env` call above
* `<secret>` - retrieved from `get-env` call above
* `<admin-user>` - needs to be the same as used in 3.x - likely `medic`
* `<uuid>` - retrieved from `get-env` call above
* `<url>` - the URL of your production instance goes here (eg `example.org`)
* `<path-to-tls>` - path to TLS files on disk

Storage Configuration Notes:

The storage related values don't need to be changed but here's an explanation:

* `preExistingDataAvailable: "true"` - If this is false, the CHT gets launched with empty data.
* `dataPathOnDiskForCouchDB: "data"` - Leave as `data` because that's the directory we created above when moving the existing data.
* `partition: "0"` - Leave as `0` to use the whole disk. If you have moved data to a separate partition in a partitioned hard disk, then you'd put the partition number here.
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
title: "Migration from Docker Compose CHT 3.x to 3-Node Clustered CHT 4.x on K3s"
linkTitle: "To K3s Multi-node"
weight: 10
description: >
Guide to migrate existing data from CHT 3.x Docker Compose deployment to CHT 4.x clustered K3s deployment with 3 CouchDB nodes
---
{{< read-content file="hosting/4.x/migration/_partial_migration_3x_docker_to_4x_k3s.md" >}}

# Create directories on secondary nodes

```shell
ssh <user>@<node2-hostname> "sudo mkdir -p /srv/couchdb2/data/shards /srv/couchdb2/data/.shards"
ssh <user>@<node3-hostname> "sudo mkdir -p /srv/couchdb3/data/shards /srv/couchdb3/data/.shards"
```

## Create values.yaml for K3s Deployment
{{< read-content file="hosting/4.x/migration/_partial_values_explanation.md" >}}

```yaml
project_name: "<your-namespace>"
namespace: "<your-namespace>"
chtversion: <version>

upstream_servers:
docker_registry: "public.ecr.aws/medic"
builds_url: "https://staging.dev.medicmobile.org/_couch/builds_4"
upgrade_service:
tag: 0.32

couchdb:
password: "<password>"
secret: "<secret>"
user: "<admin-user>"
uuid: "<uuid>"
clusteredCouch_enabled: true
couchdb_node_storage_size: 100Gi

clusteredCouch:
noOfCouchDBNodes: 3

ingress:
host: "<url>"

environment: "remote"
cluster_type: "k3s-k3d"
cert_source: "specify-file-path"
certificate_crt_file_path: "<path-to-tls>/fullchain.crt"
certificate_key_file_path: "<path-to-tls>/privkey.key"

nodes:
node-1: "couch01"
node-2: "couch02"
node-3: "couch03"

couchdb_data:
preExistingDataAvailable: "true"
dataPathOnDiskForCouchDB: "data"
partition: "0"

local_storage:
preExistingDiskPath-1: "/srv/couchdb1"
preExistingDiskPath-2: "/srv/couchdb2"
preExistingDiskPath-3: "/srv/couchdb3"
```

## Deploy to K3s

We are going to use cht-deploy from the [cht-core](https://github.com/medic/cht-core) repo.

```shell
cd cht-core/scripts/deploy
./cht-deploy -f /path/to/your/values.yaml
```

## Get Shard Distribution Instructions

Access the primary CouchDB pod, being sure to replace `<your-namespace>` with the name of your actual namespace:

```shell
kubectl exec -it -n <your-namespace> $(kubectl get pod -n <your-namespace> -l cht.service=couchdb-1 -o name) -- bash
```

Set up the migration tool:
```shell
curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
apt install -y nodejs npm git
git clone https://github.com/medic/couchdb-migration.git
cd couchdb-migration
npm ci --omit=dev

# Create a global symlink to enable running commands directly
# Note: This may require sudo if npm's global directories aren't writable
npm link

export ADMIN_USER=<admin-user>
export ADMIN_PASSWORD=<password>
export COUCH_URL="http://${ADMIN_USER}:${ADMIN_PASSWORD}@localhost:5984"

# Get shard distribution instructions
shard_matrix=$(generate-shard-distribution-matrix)
shard-move-instructions $shard_matrix
```

Example output:
```
Move <mainNode-Path>/shards/00000000-1fffffff to <[email protected]>/shards/00000000-1fffffff
Move <mainNode-Path>/.shards/00000000-1fffffff to <[email protected]>/.shards/00000000-1fffffff
Move <mainNode-Path>/shards/20000000-3fffffff to <[email protected]>/shards/20000000-3fffffff
...
```

{{% alert title="Note" %}}
The actual shard ranges in your output may differ. Adjust the following rsync commands to match your specific shard distribution instructions.
{{% /alert %}}

## Distribute Shards

Move shards to Node 2:
```shell
# Copy main shards first
sudo rsync -avz --progress --partial --partial-dir=/tmp/rsync-partial \
/srv/couchdb1/data/shards/20000000-3fffffff \
/srv/couchdb1/data/shards/80000000-9fffffff \
/srv/couchdb1/data/shards/e0000000-ffffffff \
user@node2-hostname:/srv/couchdb2/data/shards/

# Then copy hidden shards
sudo rsync -avz --progress --partial --partial-dir=/tmp/rsync-partial \
/srv/couchdb1/data/.shards/20000000-3fffffff \
/srv/couchdb1/data/.shards/80000000-9fffffff \
/srv/couchdb1/data/.shards/e0000000-ffffffff \
user@node2-hostname:/srv/couchdb2/data/.shards/

# Touch the .shards to ensure they're newer
ssh user@node2-hostname "sudo find /srv/couchdb2/data/.shards -type f -exec touch {} +"
```

Move shards to Node 3:
```shell
# Copy main shards first
sudo rsync -avz --progress --partial --partial-dir=/tmp/rsync-partial \
/srv/couchdb1/data/shards/40000000-5fffffff \
/srv/couchdb1/data/shards/a0000000-bfffffff \
user@node3-hostname:/srv/couchdb3/data/shards/

# Then copy hidden shards
sudo rsync -avz --progress --partial --partial-dir=/tmp/rsync-partial \
/srv/couchdb1/data/.shards/40000000-5fffffff \
/srv/couchdb1/data/.shards/a0000000-bfffffff \
user@node3-hostname:/srv/couchdb3/data/.shards/

# Touch the .shards to ensure they're newer
ssh user@node3-hostname "sudo find /srv/couchdb3/data/.shards -type f -exec touch {} +"
```

## Update Cluster Configuration

In the primary CouchDB pod:
```shell
# Apply shard distribution
move-shards $shard_matrix

# Remove old node configuration
remove-node [email protected]

# Verify migration
verify
```
Loading