diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..adbbf680 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +target/ +**/target/ +.idea/ diff --git a/.env b/.env new file mode 100644 index 00000000..9858b1d2 --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +SERVER_PUBLIC_DOMAIN="http://didcomm-mediator.com" +SERVER_LOCAL_PORT="8080" +STORAGE_DIRPATH="crates/generic-server/target/storage" +MONGO_DBN="mediator-coordination" + diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml deleted file mode 100644 index a59e9d7c..00000000 --- a/.github/workflows/CD.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: CD - -on: - push: - branches: [main] - -jobs: - deploy: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Rust - uses: actions/setup-rust@v1 - with: - rust-version: stable - - # Deploy to AWS EC2 Or another instance diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml new file mode 100644 index 00000000..614814c0 --- /dev/null +++ b/.github/workflows/package.yml @@ -0,0 +1,44 @@ +name: Publish Image + +on: + push: + branches: + - '*' + tags: + - 'v*' + +env: + IMAGE_NAME: didcomm-mediator-rs + +jobs: + push: + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + + steps: + - uses: actions/checkout@v4 + + - name: Build image + run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" + + - name: Log in to registry + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Push image + run: | + IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME + + # Ensure all uppercase characters are converted to lowercase + IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') + # Strip the git ref prefix from the version + VERSION=latest + # Remove the "v" prefix from the tag name + [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') + # Use "latest" tag for the main branch + [ "$VERSION" == "main" ] && VERSION=latest + echo IMAGE_ID=$IMAGE_ID + echo VERSION=$VERSION + docker tag $IMAGE_NAME $IMAGE_ID:$VERSION + docker push $IMAGE_ID:$VERSION diff --git a/.gitignore b/.gitignore index ba3de5ca..f1cdb4f6 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ Cargo.lock # Environment variables files .env.example -.env + # Reference crate mediator-server diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a7be19ee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +FROM rust:latest as builder + +WORKDIR /app + +COPY . . + +# Build the server +RUN cargo build --release + +# Use a minimal image for running the server +FROM ubuntu + +RUN apt update && apt install -y libpq5 && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Set the storage directory path +ENV STORAGE_DIRPATH="crates/generic-server/target/storage" + +# Copy the built binary +COPY --from=builder /app/target/release/didcomm-mediator /usr/local/bin/didcomm-mediator + +COPY .env .env + +# Expose the necessary port +EXPOSE 3000 + +# Set an entrypoint script to handle the environment file +ENTRYPOINT ["didcomm-mediator"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..0bbc6986 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +version: "3.8" +services: + mediator: + build: + context: . + container_name: didcomm-mediator + ports: + - "8080:8080" + env_file: + - .env + depends_on: + - mongodb + networks: + - mediator-network + + mongodb: + image: mongo:latest + container_name: mongodb + env_file: + - .env + volumes: + - mongo-data:/data/db + networks: + - mediator-network + ports: + - "27017:27017" + +networks: + mediator-network: + driver: bridge + +volumes: + mongo-data: diff --git a/docs/deployment-environment-doc.md b/docs/deployment-environment-doc.md new file mode 100644 index 00000000..67e3aa20 --- /dev/null +++ b/docs/deployment-environment-doc.md @@ -0,0 +1,81 @@ + +# **Application Deployment Documentation** + +## **1. Prerequisites** +- **Tools and Software Required**: + - Helm version (e.g., `Helm 3.x`) + - Kubernetes version (e.g., `1.25+`) + - Minikube/Cluster setup + - Other dependencies (e.g., Docker, kubectl, etc.) +- **Environment Setup**: + - Access to the Kubernetes cluster + - Required configurations or credentials + + +## **3. Helm Chart Structure** +- **Chart Overview**: + - Structure of the Helm chart (values.yaml, templates, etc.). + - Purpose of critical templates (e.g., Deployment, Service, ConfigMap). + - Default vs. custom configurations. +- **Customization**: + - How to override values.yaml using custom configurations. + Example: + ```bash + helm install mediator ./mediator-charts --values custom-values.yaml + ``` + - mandatory values are; + + **MONGO_DBN**, + **MONGO_URI**, + **SERVER_LOCAL_PORT** and + **SERVER_PUBLIC_DOMAIN** + + +## **4. Deployment Guide** +- **Steps to Deploy**: + 1. Clone the repository: + ```bash + git clone https://github.com/adorsys/didcomm-mediator-rs.git + ``` + 2. Install dependencies: + ```bash + helm dependency update mediator-charts + ``` + 3. Deploy using Helm: + ```bash + helm install mediator mediator-charts --namespace didcomm-mediator + ``` + 4. Verify deployment status: + ```bash + kubectl get pods -n didcomm-mediator + kubectl get services -n didcomm-mediator + ``` +- **Notes on Namespaces**: + - Importance of creating and using the correct namespace. +- **Rollback Instructions**: + - How to roll back to a previous release: + ```bash + helm rollback my-app + ``` + +--- + +## **5. Accessing the Application** +- **Port Forwarding**: + - Steps to forward the service ports locally for testing: + ```bash + kubectl port-forward service/ 8080: + ``` +- **Ingress/LoadBalancer Details**: + - Steps to access the application if exposed via Ingress or LoadBalancer. + +## **7. Monitoring and Debugging** +- **Logs**: + - How to fetch logs for debugging: + ```bash + kubectl logs -n didcomm-mediator + ``` +- **Monitoring Tools**: + - Mention tools used (e.g., Prometheus, Grafana, ELK Stack). + - Steps to configure and access monitoring dashboards. + diff --git a/mediator-charts/.helmignore b/mediator-charts/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/mediator-charts/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/mediator-charts/Chart.yaml b/mediator-charts/Chart.yaml new file mode 100644 index 00000000..4c76dd45 --- /dev/null +++ b/mediator-charts/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: mediator-charts +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.1.9" diff --git a/mediator-charts/templates/env-configmap.yaml b/mediator-charts/templates/env-configmap.yaml new file mode 100644 index 00000000..5d1ca750 --- /dev/null +++ b/mediator-charts/templates/env-configmap.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +data: + MONGO_DBN: mediatorDB + MONGO_URI: mongodb://mongodb:27017 + SERVER_LOCAL_PORT: "3000" + SERVER_PUBLIC_DOMAIN: http://alice-mediator.com + +kind: ConfigMap +metadata: + namespace: {{ .Values.namespace }} + creationTimestamp: null + labels: + io.kompose.service: mediator-env + name: env + + diff --git a/mediator-charts/templates/mediator-deployment.yaml b/mediator-charts/templates/mediator-deployment.yaml new file mode 100644 index 00000000..18e9b0b4 --- /dev/null +++ b/mediator-charts/templates/mediator-deployment.yaml @@ -0,0 +1,47 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-mediator-deployment + namespace: {{ .Values.namespace }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ .Release.Name }}-mediator + template: + metadata: + labels: + app: {{ .Release.Name }}-mediator + spec: + containers: + - name: {{ .Release.Name }}-mediator-container + image: {{ .Values.mediator.image.repository }}:{{ .Values.mediator.image.tag }} + imagePullPolicy: {{ .Values.mediator.image.pullPolicy }} + ports: + - containerPort: 3000 + env: + - name: MONGO_DBN + valueFrom: + configMapKeyRef: + key: MONGO_DBN + name: env + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-secret + key: password + - name: MONGO_HOST + value: {{ .Release.Name }}-mongodb-service + - name: MONGO_URI + value: "mongodb://{{ .Release.Name }}-mongodb-service:27017" + - name: SERVER_LOCAL_PORT + valueFrom: + configMapKeyRef: + key: SERVER_LOCAL_PORT + name: env + - name: SERVER_PUBLIC_DOMAIN + valueFrom: + configMapKeyRef: + key: SERVER_PUBLIC_DOMAIN + name: env + \ No newline at end of file diff --git a/mediator-charts/templates/mediator-service.yaml b/mediator-charts/templates/mediator-service.yaml new file mode 100644 index 00000000..87051bd6 --- /dev/null +++ b/mediator-charts/templates/mediator-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-mediator-service + annotations: + external-dns.alpha.kubernetes.io/hostname: {{ .Values.externalDnsHostname }} + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: {{ .Values.certificateArn }} + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https" + namespace: {{ .Values.namespace }} +spec: + selector: + app: {{ .Release.Name }}-mediator + ports: + - name: https + port: 443 + targetPort: 3000 + type: LoadBalancer diff --git a/mediator-charts/templates/mongodb-deployment.yaml b/mediator-charts/templates/mongodb-deployment.yaml new file mode 100644 index 00000000..8c295769 --- /dev/null +++ b/mediator-charts/templates/mongodb-deployment.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-mongodb-deployment + namespace: {{ .Values.namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ .Release.Name }}-mongodb + template: + metadata: + labels: + app: {{ .Release.Name }}-mongodb + spec: + containers: + - name: mongodb + image: mongo:latest + ports: + - containerPort: 27017 + resources: {} + env: + - name: MONGO_DBN + valueFrom: + configMapKeyRef: + name: env + key: MONGO_DBN + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-secret + key: password + volumeMounts: + - name: {{ .Release.Name }}-mongo-persistent-storage + mountPath: {{ .Values.mongoVolume.mountPath }} + restartPolicy: Always + volumes: + - name: {{ .Release.Name }}-mongo-persistent-storage + persistentVolumeClaim: + claimName: {{ .Release.Name }}-mongo-pvc diff --git a/mediator-charts/templates/mongodb-pv.yaml b/mediator-charts/templates/mongodb-pv.yaml new file mode 100644 index 00000000..3472270e --- /dev/null +++ b/mediator-charts/templates/mongodb-pv.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{ .Release.Name }}-mongo-pv + namespace: {{ .Values.namespace }} +spec: + capacity: + storage: {{ .Values.mongoVolume.persistentVolume.storageSize }} + accessModes: + - ReadWriteOnce + hostPath: + path: {{ .Values.mongoVolume.persistentVolume.pathOnHost }} \ No newline at end of file diff --git a/mediator-charts/templates/mongodb-pvc.yaml b/mediator-charts/templates/mongodb-pvc.yaml new file mode 100644 index 00000000..9a4034e7 --- /dev/null +++ b/mediator-charts/templates/mongodb-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-mongo-pvc + namespace: {{ .Values.namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.mongoVolume.persistentVolumeClaim.storageSize }} \ No newline at end of file diff --git a/mediator-charts/templates/mongodb-service.yaml b/mediator-charts/templates/mongodb-service.yaml new file mode 100644 index 00000000..2e5a72b8 --- /dev/null +++ b/mediator-charts/templates/mongodb-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-mongodb-service + namespace: {{ .Values.namespace }} +spec: + selector: + app: {{ .Release.Name }}-mongodb + ports: + - protocol: TCP + port: 27017 + targetPort: 27017 + type: ClusterIP + + \ No newline at end of file diff --git a/mediator-charts/templates/secrets.yaml b/mediator-charts/templates/secrets.yaml new file mode 100644 index 00000000..1fd01f05 --- /dev/null +++ b/mediator-charts/templates/secrets.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-secret + namespace: {{ .Values.namespace }} +type: Opaque +stringData: + password: root diff --git a/mediator-charts/values.yaml b/mediator-charts/values.yaml new file mode 100644 index 00000000..a2800ec8 --- /dev/null +++ b/mediator-charts/values.yaml @@ -0,0 +1,26 @@ +replicaCount: 1 +namespace: didcomm-mediator +externalDnsHostname: didcomm-mediator.eudi-adorsys.com +certificateArn: arn:aws:acm:{region}:{user id}:certificate/{id} + + + +mongodb: + databaseName: mongodb + +mediator: + image: + repository: ghcr.io/adorsys/didcomm-mediator-rs + pullPolicy: IfNotPresent + tag: latest + +mongoVolume: + persistentVolumeClaim: + storageSize: 10Gi + + persistentVolume: + storageSize: 10Gi + pathOnHost: /var/lib/mongodb + + + mountPath: /var/lib/mongodb diff --git a/src/main.rs b/src/main.rs index f9c0a739..541ef021 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,16 +6,15 @@ use std::net::SocketAddr; #[tokio::main] async fn main() -> Result<()> { // Load dotenv-flow variables - dotenv_flow::dotenv_flow().ok(); + dotenv_flow::dotenv_flow()?; // Enable logging config_tracing(); // Start server let port = std::env::var("SERVER_LOCAL_PORT").unwrap_or("3000".to_owned()); - let addr: SocketAddr = format!("0.0.0.0:{port}") - .parse() - .context("failed to parse address")?; + let ip = std::env::var("SERVER_PUBLIC_IP").unwrap_or("0.0.0.0".to_owned()); + let addr: SocketAddr = format!("{ip}:{port}").parse().unwrap(); tracing::debug!("listening on {}", addr);