Docker Community Forums

Share and learn in the Docker community.

Connect cosmos db from local web app container

I have developed a web app using next js and able to connect to the cosmos db when I run it in my local machine.

I am planning to deploy the application in azure app services.
before that I have dockerized my application and running in my machine as a container, everything is working fine except the database connection. it is throwing unexpected run time error, network error.

Could anyone help me here?

First of all, thank you to Matias Quaranta for all of the useful documentation. I had already pored over most of it before receiving his answer, but really appreciate all the time it took to compile it.

I have been struggling with this for around two weeks now and finally got something that I think will work. This work is largely based on the script found in this GitHub issue. I found that there is a PowerShell module that gets put on your computer when you install the Cosmos DB Emulator, so I tried to leverage those functions as much as possible to do the work.

The script’s entry point is the function Start-CosmosDbEmulatorForDocker and it

Makes sure the Emulator is stopped.
Generates a new certificate to be used with the Docker image and replaces the one that was created upon install of the emulator.
Generates a .pfx certificate from the one created for the emulator.
Restarts the emulator once the new certificate is ready.
The password taken by the function is the one used for the .pfx file generated.

azureCosmosDbEmulator.ps1

using namespace System.ServiceProcess

Function Start-CosmosDbEmulatorForDocker(
[Parameter()]
[securestring]
$password
) {
$cosmosDbInstallLocation = Get-CosmosDbInstallLocation
If (!$cosmosDbInstallLocation) {
Install-AzureCosmosDBEmulator
}

Write-Host “Importing Microsoft.Azure.CosmosDB.Emulator powershell module.”
Import-Module -Name “$($cosmosDbInstallLocation.InstallLocation)\PSModules\Microsoft.Azure.CosmosDB.Emulator”

Install-CosmosDBDockerCertificate -cosmosDbInstallLocation $cosmosDbInstallLocation.InstallLocation -password $password

Start-CosmosDbEmulator -AllowNetworkAccess -Key “C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==”
}

Function Get-CosmosDbInstallLocation() {
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | ForEach-Object { Get-ItemProperty _.PsPath } | Where-Object { _.DisplayName -eq “Azure Cosmos DB Emulator” } | Select-Object InstallLocation
}

Function Install-AzureCosmosDBEmulator() {
Write-Host “Installing Azure Cosmos Db Emulator.”
$installer = “$PSScriptRoot\cosmosEmulatorInstaller.msi”
curl “https://aka.ms/cosmosdb-emulator” -O $installer
Start-Process -Wait -FilePath msiexec -ArgumentList /i, $installer
Remove-Item $installer
}

Function Install-CosmosDBDockerCertificate(
[Parameter()]
[string]
$cosmosDbInstallLocation,

[Parameter()]
[securestring]
$password
) {
If ((Get-CosmosDbEmulatorStatus) -ne [ServiceControllerStatus]::Stopped) {
Write-Host “Stopping Cosmos DB emulator.”
Stop-CosmosDbEmulator
}

$dockerCertificatesPath = Join-Path (Split-Path -Path $PSScriptRoot -Parent) “certificates”
cosmosDbPfxCertificatePath = "($dockerCertificatesPath)\cosmosdbemulator.pfx"
Uninstall-Certificate -dockerCertificatePath $cosmosDbPfxCertificatePath

Write-Host “Generating new Cosmos DB certificate to work with Docker.”
New-CosmosDbEmulatorCertificate “host.docker.internal”
Start-Sleep -s 5

New-DockerCertificate -dockerCertificatePath $cosmosDbPfxCertificatePath -password $password

Set-Location (Split-Path -Path $PSScriptRoot -Parent)
}

Function Uninstall-Certificate(
[Parameter()]
[string]
$dockerCertificatePath
) {
Write-Host “Removing existing DocumentDbEmulatorCertificate certificate.”

if (Test-Path $dockerCertificatePath) {
Remove-Item -Path $dockerCertificatePath
}
}

Function New-DockerCertificate(
[Parameter()]
[string]
$dockerCertificatePath,

[Parameter()]
[securestring]
$password
) {
Write-Host “Generating new pfx version of DocumentDbEmulatorCertificate certificate for use in Docker image.”

Get-CosmosDbEmulatorCertificate | Export-PfxCertificate -Filepath $dockerCertificatePath -Password $password
}

I then have a shell script to be run inside the Docker image that will install the .pfx cert into the Docker container. The COSMOS_DB_EMULATOR_PFX_PASSWORD value must match the one used by the PowerShell script.

trust_cosmos_db_emulator_crt.sh

#!/bin/bash

Save current working directory

PWD=pwd
pushd $PWD

Find and move to the location of this script

DIR="( cd "( dirname “${BASH_SOURCE[0]}” )" && pwd )"
cd $DIR

if [ -n “$1” ]; then
COSMOS_DB_EMULATOR_PFX=$1
else
COSMOS_DB_EMULATOR_PFX="/certificates/cosmosdbemulator.pfx"
fi
COSMOS_DB_EMULATOR_PFX_PASSWORD=“SUPER_SECRET_PASSWORD”
CERT_TO_TRUST=“cosmosdbemulator.crt”

Generate .crt file if pfx exists

if [ -f “$COSMOS_DB_EMULATOR_PFX” ]; then
openssl pkcs12 -in $COSMOS_DB_EMULATOR_PFX -clcerts -nokeys -out cosmosdbemulator.crt -passin pass:$COSMOS_DB_EMULATOR_PFX_PASSWORD;
fi

# Trust Cert (will end located in /etc/ssl/certs/ based on *.crt name as a *.pem, e.g. /etc/ssl/certs/cosmosdbemulator.pem for cosmosdbemulator.crt)

if [ -f “$CERT_TO_TRUST” ]; then
cp $CERT_TO_TRUST /usr/local/share/ca-certificates/
update-ca-certificates
rm $CERT_TO_TRUST;
fi

Restore working directory

popd
The project structure I have is as follows:

src/
scripts/
azureCosmosDbEmulator.ps1
trust_cosmos_db_emulator_crt.sh
certificates/
DockerFile
The Dockerfile contains the following lines:

COPY ["/scripts/", “/scripts/”]
COPY ["/certificates/", “/certificates/”]
RUN /scripts/trust_cosmos_db_emulator_crt.sh
With all of that in place, I can build the docker image with docker build -t temp . and then run it with docker run -it -p 80:80 temp and the code running inside of the docker container will talk to my local machine’s installed version of the Azure Cosmos DB Emulator.

As this was a HUGE pain in the neck, if you are experiencing this pain as well, vote for better support from Microsoft on this here.