Skip to content
This repository has been archived by the owner on Nov 30, 2023. It is now read-only.

Add Azure Cosmos DB emulator definition #1634

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
14 changes: 14 additions & 0 deletions containers/azure-cosmosdb-dotnet-6/.devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# [Choice] .NET version: 6.0-focal, 6.0-bullseye
ARG VARIANT="6.0-focal"
FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT}

# [Choice] Node.js version: none, lts/*, 18, 16, 14
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi

# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
21 changes: 21 additions & 0 deletions containers/azure-cosmosdb-dotnet-6/.devcontainer/add-cert.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash

# Influenced by this repository.
# https://github.com/aaronpowell/FSharp.CosmosDb

set -euxo pipefail

COSMOS__ENDPOINT=https://$(docker inspect cosmos -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'):8081

# Try to get the emulator cert in a loop
until sudo curl -ksf "${COSMOS__ENDPOINT}/_explorer/emulator.pem" -o '/usr/local/share/ca-certificates/emulator.crt'; do
echo "Downloading cert from $COSMOS__ENDPOINT"
sleep 1
done

sudo update-ca-certificates

if [ ! -f ./test-project/appsettings.Development.json ]
then
echo '{ "Cosmos": { "Endpoint" : "'$COSMOS__ENDPOINT'" } }' >> ./test-project/appsettings.Development.json
fi
36 changes: 36 additions & 0 deletions containers/azure-cosmosdb-dotnet-6/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// For format details, see https://aka.ms/devcontainer.json.
{
"name": "C# (.NET) and Azure Cosmos DB Emulator",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",

// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
},

// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-azuretools.vscode-docker",
"ms-azuretools.vscode-cosmosdb",
"ms-dotnettools.csharp"
]
}
},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [ 8081 ],

"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
},

"postStartCommand": "./.devcontainer/add-cert.sh",
"features": {
"docker-from-docker": "latest"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
version: '3'

services:
app:
build:
context: .
dockerfile: Dockerfile
args:
# Update 'VARIANT' to pick a version of .NET: 3.1-focal, 6.0-focal
VARIANT: "6.0-focal"
# Optional version of Node.js
NODE_VERSION: "none"

init: true

volumes:
- ..:/workspace:cached

# Overrides default command so things don't shut down after the process ends.
command: sleep infinity

environment:
DOTNET_ENVIRONMENT: Development
# This key is emulator's key. See https://learn.microsoft.com/en-us/azure/cosmos-db/local-emulator#authenticate-requests.
COSMOS__KEY: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==

# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:cosmosdb
# Uncomment the next line to use a non-root user for all processes.
# user: vscode

# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)

cosmosdb:
container_name: cosmos
image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest
mem_limit: 3g
cpu_count: 2
environment:
AZURE_COSMOS_EMULATOR_PARTITION_COUNT: 6
AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE: "true"
volumes:
# Forwards the local Docker socket to the container.
- /var/run/docker.sock:/var/run/docker-host.sock
4 changes: 4 additions & 0 deletions containers/azure-cosmosdb-dotnet-6/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
README.md
test-project
.vscode
.npmignore
64 changes: 64 additions & 0 deletions containers/azure-cosmosdb-dotnet-6/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# C# (.NET) and Azure Cosmos DB

## Summary

| Metadata | Value |
|----------|-------|
| *Contributors* | [Yuta Matsumura](https://github.com/tsubakimoto) |
| *Categories* | Services, Azure |
| *Definition type* | Docker Compose |
| *Published image architecture(s)* | x86-64 |
| *Available image variants* | 6.0-focal |
| *Works in Codespaces* | Yes |
| *Container host OS support* | Linux, macOS |
| *Container OS* | Ubuntu (`-focal`), Debian (`-bullseye`) |
| *Languages, platforms* | .NET, .NET Core, C#, Microsoft Azure |

## Descirption
This definition creates two containers, one for C# (.NET) and one for [Azure Cosmos DB Emulator](https://learn.microsoft.com/en-us/azure/cosmos-db/linux-emulator). VS Code will attach to the .NET Core container, and from within that container the Azure Cosmos DB Emulator container will be available on **`localhost`** port 8081. For more on the configuration of Azure Cosmos DB Emulator, see the document [Configuration options](https://learn.microsoft.com/en-us/azure/cosmos-db/linux-emulator#configuration-options)

## Using this definition

**[Optional] Include any special setup requirements here. For example:**

While the definition itself works unmodified, you can select the version of **YOUR RUNTIME HERE** the container uses by updating the `VARIANT` arg in the included `.devcontainer/devcontainer.json` file.

```json
"args": { "VARIANT": "6.0-bullseye" }
```

### Using the forwardPorts property

```json
"forwardPorts": [ 8081 ]
```

This port is used by Azure Cosmos DB Emulator to expose Explorer. The explorer can be accessed at https://localhost:8081/_explorer/index.html .

### Adding the definition to a project or codespace

1. If this is your first time using a development container, please see getting started information on [setting up](https://aka.ms/vscode-remote/containers/getting-started) Remote-Containers or [creating a codespace](https://aka.ms/ghcs-open-codespace) using GitHub Codespaces.

2. Start VS Code and open your project folder or connect to a codespace.

3. Press <kbd>F1</kbd> select and **Add Development Container Configuration Files...** command for **Remote-Containers** or **Codespaces**.

> **Note:** If needed, you can drag-and-drop the `.devcontainer` folder from this sub-folder in a locally cloned copy of this repository into the VS Code file explorer instead of using the command.

4. Select this definition. You may also need to select **Show All Definitions...** for it to appear.

5. Finally, press <kbd>F1</kbd> and run **Remote-Containers: Reopen Folder in Container** or **Codespaces: Rebuild Container** to start using the definition.

## Testing the definition

This definition includes some test code that will help you verify it is working as expected on your system. Follow these steps:

1. If this is your first time using a development container, please follow the [getting started steps](https://aka.ms/vscode-remote/containers/getting-started) to set up your machine.
2. Clone this repository.
3. Start VS Code, press <kbd>F1</kbd>, and select **Remote-Containers: Open Folder in Container...**
4. Select the `containers/azure-cosmosdb-emulator` folder.
5. After the folder has opened in the container, if prompted to restore packages in a notification, click "Restore".
6. After packages are restored, run `dotnet run --project test-project/app.csproj` in `.
7. Open the browser to [https://localhost:8081/_explorer/index.html](https://localhost:8081/_explorer/index.html).
8. You should see "Azure Cosmos DB Emulator Explorer" and see added items.
9. From here, you can add breakpoints or edit the contents of the `test-project` folder to do further testing.
8 changes: 8 additions & 0 deletions containers/azure-cosmosdb-dotnet-6/test-project/Product.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// C# record representing an item in the container
public record Product(
string id,
string category,
string name,
int quantity,
bool sale
);
77 changes: 77 additions & 0 deletions containers/azure-cosmosdb-dotnet-6/test-project/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// https://learn.microsoft.com/en-us/azure/cosmos-db/sql/quickstart-dotnet

using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.Configuration;

// Get an environment name from environment variable
string environmentName = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Development";

// Build a config object, using env vars and JSON providers.
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{environmentName}.json")
.AddEnvironmentVariables()
.Build();

// New instance of CosmosClient class
using CosmosClient client = new(
accountEndpoint: config.GetValue<string>("Cosmos:Endpoint")!,
authKeyOrResourceToken: config.GetValue<string>("Cosmos:Key")!
);

// Database reference with creation if it does not already exist
Database database = await client.CreateDatabaseIfNotExistsAsync(
id: "adventureworks"
);

Console.WriteLine($"New database:\t{database.Id}");

// Container reference with creation if it does not alredy exist
Container container = await database.CreateContainerIfNotExistsAsync(
id: "products",
partitionKeyPath: "/category",
throughput: 400
);

Console.WriteLine($"New container:\t{container.Id}");

// Create new object and upsert (create or replace) to container
Product newItem = new(
id: "68719518391",
category: "gear-surf-surfboards",
name: "Yamba Surfboard",
quantity: 12,
sale: false
);

Product createdItem = await container.UpsertItemAsync<Product>(
item: newItem,
partitionKey: new PartitionKey("gear-surf-surfboards")
);

Console.WriteLine($"Created item:\t{createdItem.id}\t[{createdItem.category}]");

// Point read item from container using the id and partitionKey
Product readItem = await container.ReadItemAsync<Product>(
id: "68719518391",
partitionKey: new PartitionKey("gear-surf-surfboards")
);

// Create query using a SQL string and parameters
var query = new QueryDefinition(
query: "SELECT * FROM products p WHERE p.category = @key"
)
.WithParameter("@key", "gear-surf-surfboards");

using FeedIterator<Product> feed = container.GetItemQueryIterator<Product>(
queryDefinition: query
);

while (feed.HasMoreResults)
{
FeedResponse<Product> response = await feed.ReadNextAsync();
foreach (Product item in response)
{
Console.WriteLine($"Found item:\t{item.name}");
}
}
24 changes: 24 additions & 0 deletions containers/azure-cosmosdb-dotnet-6/test-project/app.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.*" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"Cosmos": {
"Endpoint": "",
"Key": ""
}
}