Skip to content

Commit

Permalink
Build Alpine (musl) version of the CLR Profiler (DataDog#621)
Browse files Browse the repository at this point in the history
Issue
Previously, only one version of the CLR Profiler was built for Linux distributions, and the library linked against glibc as the C standard library. Musl-based distributions (meaning they use musl as the C standard library instead of glibc) then required a combination of additional `libc6-compat` and `gcompat` packages to properly load and run the profiler library. However, on Alpine versions 3.10+ the additional compatibility packages fail and we're left with no support for these distributions.

Changes proposed in this pull request:
- Build `Datadog.Trace.ClrProfiler.Native.so` on an Alpine container so it is linked against musl, and package it as `datadog-dotnet-apm-$VERSION-musl.tar.gz`.
- Create new Alpine dockerfiles and docker-compose services for building, testing, and packaging the new version of the library in parallel with the existing Linux pipelines. Note: There are currently no apk packages for .NET Core so there is a separate dockerfile for each version of the .NET Core runtime on Alpine image. 
- Modify the IntegrationTests bash file to directly invoke `dotnet vstest` so the command directly tests the test binaries instead of trying to rebuild the test projects, which causes issues on the Alpine images that only have .NET Core SDK installed
- Add a minimal ConsoleApp .NET Core app that shows how to build a Docker container with the automatic instrumentation for a Debian container and various Alpine containers
- Run Datadog.Trace.IntegrationTests.csproj and Datadog.Trace.OpenTracing.IntegrationTests.csproj in Windows integration-tests CI run
  • Loading branch information
zacharycmontoya authored Feb 11, 2020
1 parent 49edc6d commit d584520
Show file tree
Hide file tree
Showing 20 changed files with 456 additions and 10 deletions.
74 changes: 74 additions & 0 deletions .azure-pipelines/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,66 @@ jobs:
testResultsFiles: test/**/*.trx
condition: succeededOrFailed()

- job: Alpine_Linux
strategy:
matrix:
netcoreapp2_1:
dotnetCoreSdkVersion: 2.1.x
publishTargetFramework: netcoreapp2.1
netcoreapp3_0:
dotnetCoreSdkVersion: 3.0.x
publishTargetFramework: netcoreapp3.0
netcoreapp3_1:
dotnetCoreSdkVersion: 3.1.x
publishTargetFramework: netcoreapp3.1

pool:
vmImage: ubuntu-16.04

variables:
TestAllPackageVersions: true

steps:
- task: DockerCompose@0
displayName: docker-compose run build
inputs:
containerregistrytype: Container Registry
dockerComposeCommand: run -e TestAllPackageVersions=true -e buildConfiguration=$(buildConfiguration) -e publishTargetFramework=$(publishTargetFramework) build

- task: DockerCompose@0
displayName: docker-compose run Profiler.Alpine
inputs:
containerregistrytype: Container Registry
dockerComposeCommand: run Profiler.Alpine

- task: DockerCompose@0
displayName: docker-compose run IntegrationTests.Alpine.Core21
condition: eq(variables['publishTargetFramework'], 'netcoreapp2.1')
inputs:
containerregistrytype: Container Registry
dockerComposeCommand: run -e TestAllPackageVersions=true -e buildConfiguration=$(buildConfiguration) IntegrationTests.Alpine.Core21

- task: DockerCompose@0
displayName: docker-compose run IntegrationTests.Alpine.Core30
condition: eq(variables['publishTargetFramework'], 'netcoreapp3.0')
inputs:
containerregistrytype: Container Registry
dockerComposeCommand: run -e TestAllPackageVersions=true -e buildConfiguration=$(buildConfiguration) IntegrationTests.Alpine.Core30

- task: DockerCompose@0
displayName: docker-compose run IntegrationTests.Alpine.Core31
condition: eq(variables['publishTargetFramework'], 'netcoreapp3.1')
inputs:
containerregistrytype: Container Registry
dockerComposeCommand: run -e TestAllPackageVersions=true -e buildConfiguration=$(buildConfiguration) IntegrationTests.Alpine.Core31

- task: PublishTestResults@2
displayName: publish test results
inputs:
testResultsFormat: VSTest
testResultsFiles: test/**/*.trx
condition: succeededOrFailed()

- job: Windows

pool:
Expand Down Expand Up @@ -165,7 +225,9 @@ jobs:
projects: |
reproductions/**/*.csproj
samples/**/*.csproj
test/Datadog.Trace.IntegrationTests/Datadog.Trace.IntegrationTests.csproj
test/Datadog.Trace.ClrProfiler.IntegrationTests/Datadog.Trace.ClrProfiler.IntegrationTests.csproj
test/Datadog.Trace.OpenTracing.IntegrationTests/Datadog.Trace.OpenTracing.IntegrationTests.csproj
!reproductions/**/ExpenseItDemo*.csproj
!reproductions/**/EntityFramework6x*.csproj
vstsFeed: $(packageFeed)
Expand All @@ -177,7 +239,9 @@ jobs:
projects: |
reproductions/**/*.csproj
samples/**/*.csproj
test/Datadog.Trace.IntegrationTests/Datadog.Trace.IntegrationTests.csproj
test/Datadog.Trace.ClrProfiler.IntegrationTests/Datadog.Trace.ClrProfiler.IntegrationTests.csproj
test/Datadog.Trace.OpenTracing.IntegrationTests/Datadog.Trace.OpenTracing.IntegrationTests.csproj
!reproductions/**/ExpenseItDemo*.csproj
!reproductions/**/EntityFramework6x*.csproj
arguments: --configuration $(buildConfiguration) -p:Platform=$(buildPlatform) -p:ManagedProfilerOutputDirectory=$(publishOutput)
Expand Down Expand Up @@ -209,6 +273,16 @@ jobs:
# filePath: './ci/install-sqlserver.ps1'
# enabled: false

- task: DotNetCoreCLI@2
displayName: dotnet test
inputs:
command: test
configuration: $(buildConfiguration)
projects: |
test/Datadog.Trace.IntegrationTests/Datadog.Trace.IntegrationTests.csproj
test/Datadog.Trace.OpenTracing.IntegrationTests/Datadog.Trace.OpenTracing.IntegrationTests.csproj
arguments: '-p:Platform=$(buildPlatform)'

- task: DotNetCoreCLI@2
displayName: dotnet test
inputs:
Expand Down
53 changes: 53 additions & 0 deletions .azure-pipelines/packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,56 @@ jobs:
inputs:
artifactName: linux-packages
targetPath: deploy/linux

- job: linux_alpine_packages

pool:
vmImage: ubuntu-16.04

steps:
- task: UseDotNet@2
displayName: install dotnet core sdk
inputs:
version: $(dotnetCoreSdkVersion)

- task: DotNetCoreCLI@2
displayName: dotnet restore
inputs:
command: restore
projects: src/**/*.csproj
vstsFeed: $(packageFeed)

- task: DotNetCoreCLI@2
displayName: dotnet build
inputs:
command: build
projects: src/**/*.csproj
arguments: --configuration $(buildConfiguration)

- task: DotNetCoreCLI@2
displayName: dotnet publish Datadog.Trace.ClrProfiler.Managed --framework netstandard2.0
inputs:
command: publish
publishWebProjects: false
modifyOutputPath: false
zipAfterPublish: false
projects: src/Datadog.Trace.ClrProfiler.Managed/Datadog.Trace.ClrProfiler.Managed.csproj
arguments: --configuration $(buildConfiguration) --framework netstandard2.0 --output $(publishOutput)/netstandard2.0

- task: DockerCompose@0
displayName: docker-compose run Profiler.Alpine
inputs:
containerregistrytype: Container Registry
dockerComposeCommand: run Profiler.Alpine

- task: DockerCompose@0
displayName: docker-compose run package.alpine
inputs:
containerregistrytype: Container Registry
dockerComposeCommand: run package.alpine

- task: PublishPipelineArtifact@0
displayName: publish artifacts
inputs:
artifactName: linux-alpine-packages
targetPath: deploy/linux
2 changes: 2 additions & 0 deletions customer-samples/ConsoleApp/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin\
obj\
31 changes: 31 additions & 0 deletions customer-samples/ConsoleApp/Alpine3.10.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -f netcoreapp3.1 -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/core/runtime:3.1-alpine3.10
WORKDIR /app
COPY --from=build /app/out .

# Set up Datadog APM
RUN apk --no-cache update && apk add curl
ARG TRACER_VERSION=1.12.0
RUN mkdir -p /var/log/datadog
RUN mkdir -p /opt/datadog
RUN curl -L https://github.com/DataDog/dd-trace-dotnet/releases/download/v${TRACER_VERSION}/datadog-dotnet-apm-${TRACER_VERSION}-musl.tar.gz \
| tar xzf - -C /opt/datadog

ENV CORECLR_ENABLE_PROFILING=1
ENV CORECLR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8}
ENV CORECLR_PROFILER_PATH=/opt/datadog/Datadog.Trace.ClrProfiler.Native.so
ENV DD_INTEGRATIONS=/opt/datadog/integrations.json
ENV DD_DOTNET_TRACER_HOME=/opt/datadog

CMD ["dotnet", "ConsoleApp.dll"]
31 changes: 31 additions & 0 deletions customer-samples/ConsoleApp/Alpine3.9.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -f netcoreapp2.1 -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/core/runtime:2.1-alpine3.9
WORKDIR /app
COPY --from=build /app/out .

# Set up Datadog APM
RUN apk --no-cache update && apk add curl
ARG TRACER_VERSION=1.12.0
RUN mkdir -p /var/log/datadog
RUN mkdir -p /opt/datadog
RUN curl -L https://github.com/DataDog/dd-trace-dotnet/releases/download/v${TRACER_VERSION}/datadog-dotnet-apm-${TRACER_VERSION}-musl.tar.gz \
| tar xzf - -C /opt/datadog

ENV CORECLR_ENABLE_PROFILING=1
ENV CORECLR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8}
ENV CORECLR_PROFILER_PATH=/opt/datadog/Datadog.Trace.ClrProfiler.Native.so
ENV DD_INTEGRATIONS=/opt/datadog/integrations.json
ENV DD_DOTNET_TRACER_HOME=/opt/datadog

CMD ["dotnet", "ConsoleApp.dll"]
8 changes: 8 additions & 0 deletions customer-samples/ConsoleApp/ConsoleApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
</PropertyGroup>

</Project>
30 changes: 30 additions & 0 deletions customer-samples/ConsoleApp/Debian.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -f netcoreapp3.1 -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/core/runtime:3.1
WORKDIR /app
COPY --from=build /app/out .

# Set up Datadog APM
ARG TRACER_VERSION=1.12.0
RUN mkdir -p /var/log/datadog
RUN mkdir -p /opt/datadog
RUN curl -LO https://github.com/DataDog/dd-trace-dotnet/releases/download/v${TRACER_VERSION}/datadog-dotnet-apm_${TRACER_VERSION}_amd64.deb
RUN dpkg -i ./datadog-dotnet-apm_${TRACER_VERSION}_amd64.deb

ENV CORECLR_ENABLE_PROFILING=1
ENV CORECLR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8}
ENV CORECLR_PROFILER_PATH=/opt/datadog/Datadog.Trace.ClrProfiler.Native.so
ENV DD_INTEGRATIONS=/opt/datadog/integrations.json
ENV DD_DOTNET_TRACER_HOME=/opt/datadog

CMD ["dotnet", "ConsoleApp.dll"]
22 changes: 22 additions & 0 deletions customer-samples/ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
internal class Program
{
private static async Task<int> Main()
{
var baseAddress = new Uri("https://www.example.com/");
var regularHttpClient = new HttpClient { BaseAddress = baseAddress };

Console.WriteLine("Calling regularHttpClient.GetAsync");
await regularHttpClient.GetAsync("default-handler");
Console.WriteLine("Called regularHttpClient.GetAsync");

return 0;
}
}
}
12 changes: 12 additions & 0 deletions customer-samples/ConsoleApp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# .NET Core Docker Sample
This sample demonstrates how to build container images for .NET Core apps that use the Datadog .NET Tracer.

The instructions assume that you have cloned this repo, have [Docker](https://www.docker.com/products/docker) installed, and have a command prompt open in the `customer-samples/ConsoleApp` directory.

## Build a .NET Core image
You can build and run a .NET Core-based container image using the following instructions, specifying the desire dockerfile with the `-f` argument:

```console
docker build -f Debian.dockerfile -t consoleapp .
docker run --rm -it consoleapp
```
6 changes: 6 additions & 0 deletions customer-samples/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project>
<!--
This file intentionally left blank...
to stop msbuild from looking up the folder hierarchy
-->
</Project>
Loading

0 comments on commit d584520

Please sign in to comment.