From bc384bd92977e8cd8b9c9c4cf5eb98ba48e02862 Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Mon, 10 Oct 2022 19:13:49 -0700 Subject: [PATCH 1/9] Add container-azure-* templates --- container-azure-csharp/${PROJECT}.csproj | 17 + container-azure-csharp/.gitignore | 353 ++++++++++++++++++ container-azure-csharp/Program.cs | 108 ++++++ container-azure-csharp/Pulumi.yaml | 15 + container-azure-csharp/app/App.csproj | 8 + container-azure-csharp/app/Dockerfile | 13 + container-azure-csharp/app/Program.cs | 6 + .../app/Properties/launchSettings.json | 28 ++ .../app/appsettings.Development.json | 8 + container-azure-csharp/app/appsettings.json | 9 + container-azure-go/Pulumi.yaml | 15 + container-azure-go/app/Dockerfile | 11 + container-azure-go/app/go.mod | 3 + container-azure-go/app/main.go | 19 + container-azure-go/go.mod | 84 +++++ container-azure-go/main.go | 128 +++++++ container-azure-python/.gitignore | 2 + container-azure-python/Pulumi.yaml | 18 + container-azure-python/__main__.py | 98 +++++ container-azure-python/app/Dockerfile | 8 + container-azure-python/app/app.py | 7 + container-azure-python/app/requirements.txt | 1 + container-azure-python/requirements.txt | 4 + container-azure-typescript/.gitignore | 2 + container-azure-typescript/Pulumi.yaml | 16 + container-azure-typescript/app/.dockerignore | 2 + container-azure-typescript/app/Dockerfile | 9 + container-azure-typescript/app/index.js | 15 + container-azure-typescript/app/package.json | 11 + container-azure-typescript/index.ts | 94 +++++ container-azure-typescript/package.json | 13 + container-azure-typescript/tsconfig.json | 18 + 32 files changed, 1143 insertions(+) create mode 100644 container-azure-csharp/${PROJECT}.csproj create mode 100644 container-azure-csharp/.gitignore create mode 100644 container-azure-csharp/Program.cs create mode 100644 container-azure-csharp/Pulumi.yaml create mode 100644 container-azure-csharp/app/App.csproj create mode 100644 container-azure-csharp/app/Dockerfile create mode 100644 container-azure-csharp/app/Program.cs create mode 100644 container-azure-csharp/app/Properties/launchSettings.json create mode 100644 container-azure-csharp/app/appsettings.Development.json create mode 100644 container-azure-csharp/app/appsettings.json create mode 100644 container-azure-go/Pulumi.yaml create mode 100644 container-azure-go/app/Dockerfile create mode 100644 container-azure-go/app/go.mod create mode 100644 container-azure-go/app/main.go create mode 100644 container-azure-go/go.mod create mode 100644 container-azure-go/main.go create mode 100644 container-azure-python/.gitignore create mode 100644 container-azure-python/Pulumi.yaml create mode 100644 container-azure-python/__main__.py create mode 100644 container-azure-python/app/Dockerfile create mode 100644 container-azure-python/app/app.py create mode 100644 container-azure-python/app/requirements.txt create mode 100644 container-azure-python/requirements.txt create mode 100644 container-azure-typescript/.gitignore create mode 100644 container-azure-typescript/Pulumi.yaml create mode 100644 container-azure-typescript/app/.dockerignore create mode 100644 container-azure-typescript/app/Dockerfile create mode 100644 container-azure-typescript/app/index.js create mode 100644 container-azure-typescript/app/package.json create mode 100644 container-azure-typescript/index.ts create mode 100644 container-azure-typescript/package.json create mode 100644 container-azure-typescript/tsconfig.json diff --git a/container-azure-csharp/${PROJECT}.csproj b/container-azure-csharp/${PROJECT}.csproj new file mode 100644 index 000000000..d2bf051ce --- /dev/null +++ b/container-azure-csharp/${PROJECT}.csproj @@ -0,0 +1,17 @@ +ο»Ώ + + Exe + net6.0 + enable + + + app/**;$(DefaultItemExcludes) + + + + + + + + + diff --git a/container-azure-csharp/.gitignore b/container-azure-csharp/.gitignore new file mode 100644 index 000000000..e64527066 --- /dev/null +++ b/container-azure-csharp/.gitignore @@ -0,0 +1,353 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ diff --git a/container-azure-csharp/Program.cs b/container-azure-csharp/Program.cs new file mode 100644 index 000000000..e24aafa0e --- /dev/null +++ b/container-azure-csharp/Program.cs @@ -0,0 +1,108 @@ +ο»Ώusing Pulumi; +using AzureNative = Pulumi.AzureNative; +using Docker = Pulumi.Docker; +using Random = Pulumi.Random; +using System.Collections.Generic; + +return await Pulumi.Deployment.RunAsync(() => +{ + var config = new Config(); + var appPath = config.Get("appPath") ?? "./app"; + var containerPort = config.GetInt32("containerPort") ?? 80; + var imageName = config.Get("imageName") ?? "my-app"; + + var resourceGroup = new AzureNative.Resources.ResourceGroup("resourceGroup"); + + var registry = new AzureNative.ContainerRegistry.Registry("registry", new() + { + ResourceGroupName = resourceGroup.Name, + AdminUserEnabled = true, + Sku = new AzureNative.ContainerRegistry.Inputs.SkuArgs { + Name = AzureNative.ContainerRegistry.SkuName.Basic, + }, + }); + + var credentials = AzureNative.ContainerRegistry.ListRegistryCredentials.Invoke(new() + { + ResourceGroupName = resourceGroup.Name, + RegistryName = registry.Name, + }); + + var registryUsername = credentials.Apply(result => result.Username!); + var registryPassword = credentials.Apply(result => result.Passwords[0]!.Value!); + + var image = new Docker.Image("image", new() + { + ImageName = Pulumi.Output.Format($"{registry.LoginServer}/{imageName}"), + Build = new Docker.DockerBuild { + Context = appPath, + }, + Registry = new Docker.ImageRegistry { + Server = registry.LoginServer, + Username = registryUsername, + Password = registryPassword, + }, + }); + + var hostname = new Random.RandomPet("hostname", new() + { + Length = 2, + }); + + var group = new AzureNative.ContainerInstance.ContainerGroup("group", new() + { + ResourceGroupName = resourceGroup.Name, + OsType = "linux", + RestartPolicy = "always", + ImageRegistryCredentials = new AzureNative.ContainerInstance.Inputs.ImageRegistryCredentialArgs { + Server = registry.LoginServer, + Username = registryUsername, + Password = registryPassword, + }, + Containers = new[] + { + new AzureNative.ContainerInstance.Inputs.ContainerArgs { + Name = imageName, + Image = image.ImageName, + Ports = new[] + { + new AzureNative.ContainerInstance.Inputs.ContainerPortArgs { + Port = containerPort, + Protocol = "tcp", + }, + }, + EnvironmentVariables = new[] + { + new AzureNative.ContainerInstance.Inputs.EnvironmentVariableArgs { + Name = "ASPNETCORE_URLS", + Value = $"http://0.0.0.0:{containerPort}", + }, + }, + Resources = new AzureNative.ContainerInstance.Inputs.ResourceRequirementsArgs { + Requests = new AzureNative.ContainerInstance.Inputs.ResourceRequestsArgs { + Cpu = 1.0, + MemoryInGB = 1.5, + }, + }, + }, + }, + IpAddress = new AzureNative.ContainerInstance.Inputs.IpAddressArgs { + Type = AzureNative.ContainerInstance.ContainerGroupIpAddressType.Public, + DnsNameLabel = hostname.Id, + Ports = new[] + { + new AzureNative.ContainerInstance.Inputs.PortArgs { + Port = containerPort, + Protocol = "tcp", + }, + }, + } + }); + + return new Dictionary + { + ["ipAddress"] = group.IpAddress.Apply(address => address!.Ip), + ["hostname"] = group.IpAddress.Apply(address => address!.Fqdn), + ["url"] = group.IpAddress.Apply(address => $"http://{address!.Fqdn}"), + }; +}); diff --git a/container-azure-csharp/Pulumi.yaml b/container-azure-csharp/Pulumi.yaml new file mode 100644 index 000000000..daf9e7b01 --- /dev/null +++ b/container-azure-csharp/Pulumi.yaml @@ -0,0 +1,15 @@ +name: ${PROJECT} +description: ${DESCRIPTION} +runtime: dotnet +template: + description: A containerized service on Azure Container Instances + config: + azure-native:location: + description: The Azure region to deploy into + default: WestUS + appPath: + description: The path to the container application to deploy + default: app + containerPort: + description: The port to expose on the container + default: 80 diff --git a/container-azure-csharp/app/App.csproj b/container-azure-csharp/app/App.csproj new file mode 100644 index 000000000..855c69078 --- /dev/null +++ b/container-azure-csharp/app/App.csproj @@ -0,0 +1,8 @@ + + + net6.0 + enable + enable + + + diff --git a/container-azure-csharp/app/Dockerfile b/container-azure-csharp/app/Dockerfile new file mode 100644 index 000000000..fa18e125c --- /dev/null +++ b/container-azure-csharp/app/Dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /app + +COPY *.csproj ./ +RUN dotnet restore + +COPY . ./ +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 as base +WORKDIR /app +COPY --from=build /app/out . +ENTRYPOINT ["dotnet", "App.dll"] diff --git a/container-azure-csharp/app/Program.cs b/container-azure-csharp/app/Program.cs new file mode 100644 index 000000000..bc8438c3a --- /dev/null +++ b/container-azure-csharp/app/Program.cs @@ -0,0 +1,6 @@ +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapGet("/", () => "Hello World!"); + +app.Run(); diff --git a/container-azure-csharp/app/Properties/launchSettings.json b/container-azure-csharp/app/Properties/launchSettings.json new file mode 100644 index 000000000..9911d5af1 --- /dev/null +++ b/container-azure-csharp/app/Properties/launchSettings.json @@ -0,0 +1,28 @@ +ο»Ώ{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:33060", + "sslPort": 44325 + } + }, + "profiles": { + "container_azure": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7264;http://localhost:5219", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/container-azure-csharp/app/appsettings.Development.json b/container-azure-csharp/app/appsettings.Development.json new file mode 100644 index 000000000..0e7f4af09 --- /dev/null +++ b/container-azure-csharp/app/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/container-azure-csharp/app/appsettings.json b/container-azure-csharp/app/appsettings.json new file mode 100644 index 000000000..a9a1bac2c --- /dev/null +++ b/container-azure-csharp/app/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/container-azure-go/Pulumi.yaml b/container-azure-go/Pulumi.yaml new file mode 100644 index 000000000..3bb4bfd6d --- /dev/null +++ b/container-azure-go/Pulumi.yaml @@ -0,0 +1,15 @@ +name: ${PROJECT} +description: ${DESCRIPTION} +runtime: go +template: + description: A containerized service on Azure Container Instances + config: + azure-native:location: + description: The Azure region to deploy into + default: WestUS + appPath: + description: The path to the container application to deploy + default: app + containerPort: + description: The port to expose on the container + default: 80 diff --git a/container-azure-go/app/Dockerfile b/container-azure-go/app/Dockerfile new file mode 100644 index 000000000..9369b67c4 --- /dev/null +++ b/container-azure-go/app/Dockerfile @@ -0,0 +1,11 @@ +FROM golang + +WORKDIR /usr/src/app + +COPY go.* ./ +RUN go mod download + +COPY . . +RUN go build -o /app + +ENTRYPOINT /app diff --git a/container-azure-go/app/go.mod b/container-azure-go/app/go.mod new file mode 100644 index 000000000..b16f0d7c5 --- /dev/null +++ b/container-azure-go/app/go.mod @@ -0,0 +1,3 @@ +module app + +go 1.18 diff --git a/container-azure-go/app/main.go b/container-azure-go/app/main.go new file mode 100644 index 000000000..435fa6a3c --- /dev/null +++ b/container-azure-go/app/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "os" +) + +func main() { + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello, World!") + }) + + if err := http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("PORT")), nil); err != nil { + log.Fatal(err) + } +} diff --git a/container-azure-go/go.mod b/container-azure-go/go.mod new file mode 100644 index 000000000..2225672a8 --- /dev/null +++ b/container-azure-go/go.mod @@ -0,0 +1,84 @@ +module azure-container-go + +go 1.17 + +require ( + github.com/pulumi/pulumi-azure-native/sdk v1.74.0 + github.com/pulumi/pulumi-random/sdk v1.7.0 + github.com/pulumi/pulumi-random/sdk/v4 v4.8.2 + github.com/pulumi/pulumi/sdk/v3 v3.42.0 +) + +require ( + github.com/Masterminds/semver v1.5.0 // indirect + github.com/acomagu/bufpipe v1.0.3 // indirect + github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect + github.com/blang/semver v3.5.1+incompatible // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.3.1 // indirect + github.com/go-git/go-git/v5 v5.4.2 // indirect + github.com/gofrs/flock v0.7.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-cmp v0.5.8 // indirect + github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-ps v1.0.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/term v1.1.0 // indirect + github.com/pulumi/pulumi/sdk v1.13.1 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/src-d/gcfg v1.4.0 // indirect + github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7 // indirect + github.com/xanzy/ssh-agent v0.3.2 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.12 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect + gopkg.in/src-d/go-git.v4 v4.13.1 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + lukechampine.com/frand v1.4.2 // indirect +) + +require ( + github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20220930113650-c6815a8c17ad // indirect + github.com/cheggaaa/pb v1.0.29 // indirect + github.com/cloudflare/circl v1.2.0 // indirect + github.com/djherbis/times v1.5.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/gofrs/uuid v4.3.0+incompatible // indirect + github.com/golang/glog v1.0.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/opentracing/basictracer-go v1.1.0 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pulumi/pulumi-docker/sdk/v3 v3.4.1 + github.com/rivo/uniseg v0.4.2 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.0.1 // indirect + github.com/sergi/go-diff v1.2.0 // indirect + github.com/spf13/cobra v1.5.0 // indirect + github.com/texttheater/golang-levenshtein v1.0.1 // indirect + github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect + github.com/uber/jaeger-lib v2.4.1+incompatible // indirect + go.uber.org/atomic v1.10.0 // indirect + golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b // indirect + golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect + golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect + golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect + google.golang.org/genproto v0.0.0-20220930163606-c98284e70a91 // indirect + google.golang.org/grpc v1.50.0 // indirect + sourcegraph.com/sourcegraph/appdash v0.0.0-20211028080628-e2786a622600 // indirect +) diff --git a/container-azure-go/main.go b/container-azure-go/main.go new file mode 100644 index 000000000..86db2a364 --- /dev/null +++ b/container-azure-go/main.go @@ -0,0 +1,128 @@ +package main + +import ( + "github.com/pulumi/pulumi-azure-native/sdk/go/azure/containerinstance" + "github.com/pulumi/pulumi-azure-native/sdk/go/azure/containerregistry" + "github.com/pulumi/pulumi-azure-native/sdk/go/azure/resources" + "github.com/pulumi/pulumi-docker/sdk/v3/go/docker" + "github.com/pulumi/pulumi-random/sdk/v4/go/random" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config" +) + +func main() { + pulumi.Run(func(ctx *pulumi.Context) error { + + cfg := config.New(ctx, "") + imageName := "my-app" + if param := cfg.Get("imageName"); param != "" { + imageName = param + } + appPath := "./app" + if param := cfg.Get("appPath"); param != "" { + appPath = param + } + containerPort := 80 + if param := cfg.GetInt("containerPort"); param != 0 { + containerPort = param + } + + resourceGroup, err := resources.NewResourceGroup(ctx, "resource-group", nil) + if err != nil { + return err + } + + registry, err := containerregistry.NewRegistry(ctx, "registry", &containerregistry.RegistryArgs{ + ResourceGroupName: resourceGroup.Name, + AdminUserEnabled: pulumi.Bool(true), + Sku: &containerregistry.SkuArgs{ + Name: pulumi.String(containerregistry.SkuNameBasic), + }, + }) + if err != nil { + return err + } + + credentials := containerregistry.ListRegistryCredentialsOutput(ctx, containerregistry.ListRegistryCredentialsOutputArgs{ + ResourceGroupName: resourceGroup.Name, + RegistryName: registry.Name, + }) + registryUsername := credentials.Username().Elem() + registryPassword := credentials.Passwords().Index(pulumi.Int(0)).Value().Elem() + + image, err := docker.NewImage(ctx, "image", &docker.ImageArgs{ + ImageName: pulumi.Sprintf("%s/%s", registry.LoginServer, imageName), + Build: docker.DockerBuildArgs{ + Context: pulumi.String(appPath), + }, + Registry: docker.ImageRegistryArgs{ + Server: registry.LoginServer, + Username: registryUsername, + Password: registryPassword, + }, + }) + if err != nil { + return err + } + + hostname, err := random.NewRandomPet(ctx, "hostname", &random.RandomPetArgs{ + Length: pulumi.Int(2), + }) + if err != nil { + return err + } + + group, err := containerinstance.NewContainerGroup(ctx, "group", &containerinstance.ContainerGroupArgs{ + ResourceGroupName: resourceGroup.Name, + OsType: pulumi.String("linux"), + RestartPolicy: pulumi.String("always"), + ImageRegistryCredentials: containerinstance.ImageRegistryCredentialArray{ + containerinstance.ImageRegistryCredentialArgs{ + Server: registry.LoginServer, + Username: registryUsername, + Password: registryPassword, + }, + }, + Containers: containerinstance.ContainerArray{ + containerinstance.ContainerArgs{ + Name: pulumi.String(imageName), + Image: image.ImageName, + Ports: containerinstance.ContainerPortArray{ + containerinstance.ContainerPortArgs{ + Port: pulumi.Int(containerPort), + Protocol: pulumi.String("tcp"), + }, + }, + EnvironmentVariables: containerinstance.EnvironmentVariableArray{ + containerinstance.EnvironmentVariableArgs{ + Name: pulumi.String("PORT"), + Value: pulumi.Sprintf("%d", containerPort), + }, + }, + Resources: containerinstance.ResourceRequirementsArgs{ + Requests: containerinstance.ResourceRequestsArgs{ + Cpu: pulumi.Float64(1.0), + MemoryInGB: pulumi.Float64(1.5), + }, + }, + }, + }, + IpAddress: containerinstance.IpAddressArgs{ + Type: pulumi.String("public"), + DnsNameLabel: hostname.ID(), + Ports: containerinstance.PortArray{ + containerinstance.PortArgs{ + Port: pulumi.Int(containerPort), + Protocol: pulumi.String("tcp"), + }, + }, + }, + }) + + ctx.Export("ipAddress", group.IpAddress.Elem().Ip()) + ctx.Export("hostname", group.IpAddress.Elem().Fqdn()) + ctx.Export("url", pulumi.Sprintf("http://%s:%d", group.IpAddress.Elem().Fqdn(), containerPort)) + + return nil + }) +} diff --git a/container-azure-python/.gitignore b/container-azure-python/.gitignore new file mode 100644 index 000000000..a3807e5bd --- /dev/null +++ b/container-azure-python/.gitignore @@ -0,0 +1,2 @@ +*.pyc +venv/ diff --git a/container-azure-python/Pulumi.yaml b/container-azure-python/Pulumi.yaml new file mode 100644 index 000000000..c8809ce15 --- /dev/null +++ b/container-azure-python/Pulumi.yaml @@ -0,0 +1,18 @@ +name: ${PROJECT} +description: ${DESCRIPTION} +runtime: + name: python + options: + virtualenv: venv +template: + description: A containerized service on Azure Container Instances + config: + azure-native:location: + description: The Azure region to deploy into + default: WestUS + appPath: + description: The path to the container application to deploy + default: app + containerPort: + description: The port to expose on the container + default: 80 diff --git a/container-azure-python/__main__.py b/container-azure-python/__main__.py new file mode 100644 index 000000000..6f457f91c --- /dev/null +++ b/container-azure-python/__main__.py @@ -0,0 +1,98 @@ +import pulumi +import pulumi_docker as docker +import pulumi_random as random +from pulumi_azure_native import resources, containerregistry, containerinstance + +config = pulumi.Config() +image_name = config.get("imageName", "my-app") +app_path = config.get("appPath", "./app") +container_port = config.get_number("containerPort", 80) + +resource_group = resources.ResourceGroup('resource_group') + +registry = containerregistry.Registry("registry", containerregistry.RegistryArgs( + resource_group_name=resource_group.name, + admin_user_enabled=True, + sku=containerregistry.SkuArgs( + name=containerregistry.SkuName.BASIC, + ), +)) + +credentials = containerregistry.list_registry_credentials_output( + resource_group_name=resource_group.name, + registry_name=registry.name, +) + +registry_username = credentials.apply(lambda creds: creds.username) +registry_password = credentials.apply(lambda creds: creds.passwords[0].value) + +image = docker.Image("image", + image_name=pulumi.Output.concat(registry.login_server, "/", image_name), + build=docker.DockerBuild( + context=app_path, + ), + registry=docker.ImageRegistry( + server=registry.login_server, + username=registry_username, + password=registry_password, + ), +) + +hostname = random.RandomPet("hostname", random.RandomPetArgs( + length=2, +)) + +group = containerinstance.ContainerGroup("group", containerinstance.ContainerGroupArgs( + resource_group_name=resource_group.name, + os_type="linux", + restart_policy="always", + image_registry_credentials=[ + containerinstance.ImageRegistryCredentialArgs( + server=registry.login_server, + username=registry_username, + password=registry_password, + ), + ], + containers=[ + containerinstance.ContainerArgs( + name=image_name, + image=image.image_name, + ports=[ + containerinstance.ContainerPortArgs( + port=container_port, + protocol="tcp", + ), + ], + environment_variables=[ + containerinstance.EnvironmentVariableArgs( + name="FLASK_RUN_PORT", + value=str(container_port), + ), + containerinstance.EnvironmentVariableArgs( + name="FLASK_RUN_HOST", + value="0.0.0.0", + ), + ], + resources=containerinstance.ResourceRequirementsArgs( + requests=containerinstance.ResourceRequestsArgs( + cpu=1.0, + memory_in_gb=1.5, + ), + ), + ), + ], + ip_address=containerinstance.IpAddressArgs( + type=containerinstance.ContainerGroupIpAddressType.PUBLIC, + dns_name_label=hostname, + ports=[ + containerinstance.PortArgs( + port=container_port, + protocol="tcp", + ), + ], + ), +)) + +pulumi.export("ipAddress", group.ip_address.apply(lambda addr: addr.ip)) +pulumi.export("hostname", group.ip_address.apply(lambda addr: addr.fqdn)) +pulumi.export("url", group.ip_address.apply(lambda addr: f"http://{addr.fqdn}:{container_port}")) diff --git a/container-azure-python/app/Dockerfile b/container-azure-python/app/Dockerfile new file mode 100644 index 000000000..1e2f05ac2 --- /dev/null +++ b/container-azure-python/app/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.10-alpine +WORKDIR /usr/src/app + +COPY requirements.txt requirements.txt +RUN pip install -r requirements.txt +COPY . . + +CMD ["flask", "run"] diff --git a/container-azure-python/app/app.py b/container-azure-python/app/app.py new file mode 100644 index 000000000..f34ca6f98 --- /dev/null +++ b/container-azure-python/app/app.py @@ -0,0 +1,7 @@ +from flask import Flask + +app = Flask(__name__) + +@app.route("/") +def index(): + return "Hi, world!" diff --git a/container-azure-python/app/requirements.txt b/container-azure-python/app/requirements.txt new file mode 100644 index 000000000..e3e9a71d9 --- /dev/null +++ b/container-azure-python/app/requirements.txt @@ -0,0 +1 @@ +Flask diff --git a/container-azure-python/requirements.txt b/container-azure-python/requirements.txt new file mode 100644 index 000000000..150701af6 --- /dev/null +++ b/container-azure-python/requirements.txt @@ -0,0 +1,4 @@ +pulumi>=3.0.0,<4.0.0 +pulumi-azure-native>=1.0.0,<2.0.0 +pulumi-random>=4.0.0,<5.0.0 +pulumi-docker>=3.0.0,<4.0.0 diff --git a/container-azure-typescript/.gitignore b/container-azure-typescript/.gitignore new file mode 100644 index 000000000..c6958891d --- /dev/null +++ b/container-azure-typescript/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/node_modules/ diff --git a/container-azure-typescript/Pulumi.yaml b/container-azure-typescript/Pulumi.yaml new file mode 100644 index 000000000..938093d9d --- /dev/null +++ b/container-azure-typescript/Pulumi.yaml @@ -0,0 +1,16 @@ +name: ${PROJECT} +description: ${DESCRIPTION} +runtime: + name: nodejs +template: + description: A containerized service on Azure Container Instances + config: + azure-native:location: + description: The Azure region to deploy into + default: WestUS + appPath: + description: The path to the container application to deploy + default: app + containerPort: + description: The port to expose on the container + default: 80 diff --git a/container-azure-typescript/app/.dockerignore b/container-azure-typescript/app/.dockerignore new file mode 100644 index 000000000..93f136199 --- /dev/null +++ b/container-azure-typescript/app/.dockerignore @@ -0,0 +1,2 @@ +node_modules +npm-debug.log diff --git a/container-azure-typescript/app/Dockerfile b/container-azure-typescript/app/Dockerfile new file mode 100644 index 000000000..d35a7bcf9 --- /dev/null +++ b/container-azure-typescript/app/Dockerfile @@ -0,0 +1,9 @@ +FROM node:16 + +WORKDIR /usr/src/app + +COPY package*.json ./ +RUN npm install +COPY . . + +CMD [ "node", "index.js" ] diff --git a/container-azure-typescript/app/index.js b/container-azure-typescript/app/index.js new file mode 100644 index 000000000..1778c60f3 --- /dev/null +++ b/container-azure-typescript/app/index.js @@ -0,0 +1,15 @@ +"use strict"; + +const express = require("express"); +const app = express(); + +app.get("/", (req, res) => { + res.send("Hello, world! πŸ‘‹"); +}); + +const host = "0.0.0.0"; +const port = process.env.PORT; + +app.listen(port, host, () => { + console.log(`Running on http://${host}:${port}`); +}); diff --git a/container-azure-typescript/app/package.json b/container-azure-typescript/app/package.json new file mode 100644 index 000000000..74a933871 --- /dev/null +++ b/container-azure-typescript/app/package.json @@ -0,0 +1,11 @@ +{ + "name": "my-app", + "version": "0.1.0", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "express": "^4.16.1" + } +} diff --git a/container-azure-typescript/index.ts b/container-azure-typescript/index.ts new file mode 100644 index 000000000..5b3f04762 --- /dev/null +++ b/container-azure-typescript/index.ts @@ -0,0 +1,94 @@ +import * as pulumi from "@pulumi/pulumi"; +import * as resources from "@pulumi/azure-native/resources"; +import * as containerregistry from "@pulumi/azure-native/containerregistry"; +import * as containerinstance from "@pulumi/azure-native/containerinstance"; +import * as random from "@pulumi/random"; +import * as docker from "@pulumi/docker"; + +const config = new pulumi.Config(); +const imageName = config.get("imageName") || "my-app"; +const appPath = config.get("appPath") || "./app"; +const containerPort = config.getNumber("containerPort") || 80; + +const resourceGroup = new resources.ResourceGroup("resource-group"); + +const registry = new containerregistry.Registry("registry", { + resourceGroupName: resourceGroup.name, + adminUserEnabled: true, + sku: { + name: containerregistry.SkuName.Basic, + }, +}); + +const credentials = containerregistry.listRegistryCredentialsOutput({ + resourceGroupName: resourceGroup.name, + registryName: registry.name, +}).apply(creds => { + return { + username: creds.username!, + password: creds.passwords![0].value!, + }; +}); + +const image = new docker.Image("image", { + imageName: pulumi.interpolate`${registry.loginServer}/${imageName}`, + build: { + context: appPath, + }, + registry: { + server: registry.loginServer, + username: credentials.username, + password: credentials.password, + }, +}); + +const group = new containerinstance.ContainerGroup("group", { + resourceGroupName: resourceGroup.name, + osType: "linux", + restartPolicy: "always", + imageRegistryCredentials: [ + { + server: registry.loginServer, + username: credentials.username, + password: credentials.password, + }, + ], + containers: [ + { + name: imageName, + image: image.imageName, + ports: [ + { + port: containerPort, + protocol: "tcp", + }, + ], + environmentVariables: [ + { + name: "PORT", + value: containerPort.toString(), + }, + ], + resources: { + requests: { + cpu: 1.0, + memoryInGB: 1.5, + }, + }, + }, + ], + ipAddress: { + type: containerinstance.ContainerGroupIpAddressType.Public, + dnsNameLabel: new random.RandomPet("host", { length: 2 }).id, + ports: [ + { + port: containerPort, + protocol: "tcp", + }, + ], + }, +}); + +export const ipAddress = group.ipAddress.apply(address => address!.ip!); +export const hostname = group.ipAddress.apply(address => address!.fqdn!); +export const url = group.ipAddress.apply(address => `http://${address!.fqdn!}:${containerPort}`); diff --git a/container-azure-typescript/package.json b/container-azure-typescript/package.json new file mode 100644 index 000000000..3ed6fe908 --- /dev/null +++ b/container-azure-typescript/package.json @@ -0,0 +1,13 @@ +{ + "name": "azure-container", + "main": "index.ts", + "devDependencies": { + "@types/node": "^14" + }, + "dependencies": { + "@pulumi/azure-native": "^1.0.0", + "@pulumi/docker": "^3.4.1", + "@pulumi/pulumi": "^3.0.0", + "@pulumi/random": "^4.8.2" + } +} diff --git a/container-azure-typescript/tsconfig.json b/container-azure-typescript/tsconfig.json new file mode 100644 index 000000000..ab65afa61 --- /dev/null +++ b/container-azure-typescript/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "strict": true, + "outDir": "bin", + "target": "es2016", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.ts" + ] +} From bfdf307fa04025c943a1f2883c733d91f4c2ff63 Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Fri, 14 Oct 2022 16:44:09 -0700 Subject: [PATCH 2/9] Make settings configurable, drop RandomPet --- container-azure-csharp/Program.cs | 30 +++++++++++++---------- container-azure-csharp/Pulumi.yaml | 6 +++++ container-azure-csharp/app/Program.cs | 2 +- container-azure-go/Pulumi.yaml | 6 +++++ container-azure-go/app/main.go | 2 +- container-azure-go/main.go | 34 +++++++++++++++++++------- container-azure-python/Pulumi.yaml | 6 +++++ container-azure-python/__main__.py | 25 ++++++++++--------- container-azure-python/app/app.py | 2 +- container-azure-typescript/Pulumi.yaml | 6 +++++ container-azure-typescript/index.ts | 15 ++++++++---- 11 files changed, 93 insertions(+), 41 deletions(-) diff --git a/container-azure-csharp/Program.cs b/container-azure-csharp/Program.cs index e24aafa0e..499c74e3a 100644 --- a/container-azure-csharp/Program.cs +++ b/container-azure-csharp/Program.cs @@ -1,15 +1,18 @@ -ο»Ώusing Pulumi; +ο»Ώusing System; +using System.Collections.Generic; +using Pulumi; using AzureNative = Pulumi.AzureNative; using Docker = Pulumi.Docker; using Random = Pulumi.Random; -using System.Collections.Generic; return await Pulumi.Deployment.RunAsync(() => { var config = new Config(); var appPath = config.Get("appPath") ?? "./app"; - var containerPort = config.GetInt32("containerPort") ?? 80; var imageName = config.Get("imageName") ?? "my-app"; + var containerPort = config.GetInt32("containerPort") ?? 80; + var cpu = Math.Max(config.GetObject("cpu"), 1.0); + var memory = Math.Max(config.GetObject("memory"), 1.5); var resourceGroup = new AzureNative.Resources.ResourceGroup("resourceGroup"); @@ -44,12 +47,13 @@ }, }); - var hostname = new Random.RandomPet("hostname", new() + var dnsName = new Random.RandomString("dns-name", new() { - Length = 2, - }); + Length = 8, + Special = false, + }).Result.Apply(result => $"{imageName}-{result.ToLower()}"); - var group = new AzureNative.ContainerInstance.ContainerGroup("group", new() + var containerGroup = new AzureNative.ContainerInstance.ContainerGroup("container-group", new() { ResourceGroupName = resourceGroup.Name, OsType = "linux", @@ -80,15 +84,15 @@ }, Resources = new AzureNative.ContainerInstance.Inputs.ResourceRequirementsArgs { Requests = new AzureNative.ContainerInstance.Inputs.ResourceRequestsArgs { - Cpu = 1.0, - MemoryInGB = 1.5, + Cpu = cpu, + MemoryInGB = memory, }, }, }, }, IpAddress = new AzureNative.ContainerInstance.Inputs.IpAddressArgs { Type = AzureNative.ContainerInstance.ContainerGroupIpAddressType.Public, - DnsNameLabel = hostname.Id, + DnsNameLabel = dnsName, Ports = new[] { new AzureNative.ContainerInstance.Inputs.PortArgs { @@ -101,8 +105,8 @@ return new Dictionary { - ["ipAddress"] = group.IpAddress.Apply(address => address!.Ip), - ["hostname"] = group.IpAddress.Apply(address => address!.Fqdn), - ["url"] = group.IpAddress.Apply(address => $"http://{address!.Fqdn}"), + ["ipAddress"] = containerGroup.IpAddress.Apply(addr => addr!.Ip), + ["hostname"] = containerGroup.IpAddress.Apply(addr => addr!.Fqdn), + ["url"] = containerGroup.IpAddress.Apply(addr => $"http://{addr!.Fqdn}:{containerPort}"), }; }); diff --git a/container-azure-csharp/Pulumi.yaml b/container-azure-csharp/Pulumi.yaml index daf9e7b01..80b641c0e 100644 --- a/container-azure-csharp/Pulumi.yaml +++ b/container-azure-csharp/Pulumi.yaml @@ -13,3 +13,9 @@ template: containerPort: description: The port to expose on the container default: 80 + cpu: + description: The CPU limit of the container instance + default: 1.0 + memory: + description: The memory limit, in GB, of the container instance + default: 1.5 diff --git a/container-azure-csharp/app/Program.cs b/container-azure-csharp/app/Program.cs index bc8438c3a..04ce7f50d 100644 --- a/container-azure-csharp/app/Program.cs +++ b/container-azure-csharp/app/Program.cs @@ -1,6 +1,6 @@ var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); -app.MapGet("/", () => "Hello World!"); +app.MapGet("/", () => "Hello, world! πŸ‘‹"); app.Run(); diff --git a/container-azure-go/Pulumi.yaml b/container-azure-go/Pulumi.yaml index 3bb4bfd6d..22538c61f 100644 --- a/container-azure-go/Pulumi.yaml +++ b/container-azure-go/Pulumi.yaml @@ -13,3 +13,9 @@ template: containerPort: description: The port to expose on the container default: 80 + cpu: + description: The CPU limit of the container instance + default: 1.0 + memory: + description: The memory limit, in GB, of the container instance + default: 1.5 diff --git a/container-azure-go/app/main.go b/container-azure-go/app/main.go index 435fa6a3c..710b0f0d1 100644 --- a/container-azure-go/app/main.go +++ b/container-azure-go/app/main.go @@ -10,7 +10,7 @@ import ( func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "Hello, World!") + fmt.Fprintf(w, "Hello, world! πŸ‘‹") }) if err := http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("PORT")), nil); err != nil { diff --git a/container-azure-go/main.go b/container-azure-go/main.go index 86db2a364..04c9e4e21 100644 --- a/container-azure-go/main.go +++ b/container-azure-go/main.go @@ -1,6 +1,9 @@ package main import ( + "fmt" + "strings" + "github.com/pulumi/pulumi-azure-native/sdk/go/azure/containerinstance" "github.com/pulumi/pulumi-azure-native/sdk/go/azure/containerregistry" "github.com/pulumi/pulumi-azure-native/sdk/go/azure/resources" @@ -26,6 +29,14 @@ func main() { if param := cfg.GetInt("containerPort"); param != 0 { containerPort = param } + cpu := 1.0 + if param := cfg.GetFloat64("cpu"); param != 0 { + cpu = param + } + memory := 1.0 + if param := cfg.GetFloat64("memory"); param != 0 { + memory = param + } resourceGroup, err := resources.NewResourceGroup(ctx, "resource-group", nil) if err != nil { @@ -65,14 +76,19 @@ func main() { return err } - hostname, err := random.NewRandomPet(ctx, "hostname", &random.RandomPetArgs{ - Length: pulumi.Int(2), + dnsNameSuffix, err := random.NewRandomString(ctx, "dns-name-suffix", &random.RandomStringArgs{ + Length: pulumi.Int(8), + Special: pulumi.Bool(false), }) if err != nil { return err } - group, err := containerinstance.NewContainerGroup(ctx, "group", &containerinstance.ContainerGroupArgs{ + dnsName := dnsNameSuffix.Result.ApplyT(func(result string) string { + return fmt.Sprintf("%s-%s", imageName, strings.ToLower(result)) + }).(pulumi.StringOutput) + + containerGroup, err := containerinstance.NewContainerGroup(ctx, "container-group", &containerinstance.ContainerGroupArgs{ ResourceGroupName: resourceGroup.Name, OsType: pulumi.String("linux"), RestartPolicy: pulumi.String("always"), @@ -101,15 +117,15 @@ func main() { }, Resources: containerinstance.ResourceRequirementsArgs{ Requests: containerinstance.ResourceRequestsArgs{ - Cpu: pulumi.Float64(1.0), - MemoryInGB: pulumi.Float64(1.5), + Cpu: pulumi.Float64(cpu), + MemoryInGB: pulumi.Float64(memory), }, }, }, }, IpAddress: containerinstance.IpAddressArgs{ Type: pulumi.String("public"), - DnsNameLabel: hostname.ID(), + DnsNameLabel: dnsName, Ports: containerinstance.PortArray{ containerinstance.PortArgs{ Port: pulumi.Int(containerPort), @@ -119,9 +135,9 @@ func main() { }, }) - ctx.Export("ipAddress", group.IpAddress.Elem().Ip()) - ctx.Export("hostname", group.IpAddress.Elem().Fqdn()) - ctx.Export("url", pulumi.Sprintf("http://%s:%d", group.IpAddress.Elem().Fqdn(), containerPort)) + ctx.Export("ipAddress", containerGroup.IpAddress.Elem().Ip()) + ctx.Export("hostname", containerGroup.IpAddress.Elem().Fqdn()) + ctx.Export("url", pulumi.Sprintf("http://%s:%d", containerGroup.IpAddress.Elem().Fqdn(), containerPort)) return nil }) diff --git a/container-azure-python/Pulumi.yaml b/container-azure-python/Pulumi.yaml index c8809ce15..0045be142 100644 --- a/container-azure-python/Pulumi.yaml +++ b/container-azure-python/Pulumi.yaml @@ -16,3 +16,9 @@ template: containerPort: description: The port to expose on the container default: 80 + cpu: + description: The CPU limit of the container instance + default: 1.0 + memory: + description: The memory limit, in GB, of the container instance + default: 1.5 diff --git a/container-azure-python/__main__.py b/container-azure-python/__main__.py index 6f457f91c..ff67b9bac 100644 --- a/container-azure-python/__main__.py +++ b/container-azure-python/__main__.py @@ -6,7 +6,9 @@ config = pulumi.Config() image_name = config.get("imageName", "my-app") app_path = config.get("appPath", "./app") -container_port = config.get_number("containerPort", 80) +container_port = config.get_int("containerPort", 80) +cpu = config.get_float("cpu", 1.0) +memory = config.get_float("memory", 1.5) resource_group = resources.ResourceGroup('resource_group') @@ -38,11 +40,12 @@ ), ) -hostname = random.RandomPet("hostname", random.RandomPetArgs( - length=2, -)) +dns_name = random.RandomString("dns-name", random.RandomStringArgs( + length=8, + special=False, +)).result.apply(lambda result: f"{image_name}-{result.lower()}") -group = containerinstance.ContainerGroup("group", containerinstance.ContainerGroupArgs( +container_group = containerinstance.ContainerGroup("container-group", containerinstance.ContainerGroupArgs( resource_group_name=resource_group.name, os_type="linux", restart_policy="always", @@ -75,15 +78,15 @@ ], resources=containerinstance.ResourceRequirementsArgs( requests=containerinstance.ResourceRequestsArgs( - cpu=1.0, - memory_in_gb=1.5, + cpu=cpu, + memory_in_gb=memory, ), ), ), ], ip_address=containerinstance.IpAddressArgs( type=containerinstance.ContainerGroupIpAddressType.PUBLIC, - dns_name_label=hostname, + dns_name_label=dns_name, ports=[ containerinstance.PortArgs( port=container_port, @@ -93,6 +96,6 @@ ), )) -pulumi.export("ipAddress", group.ip_address.apply(lambda addr: addr.ip)) -pulumi.export("hostname", group.ip_address.apply(lambda addr: addr.fqdn)) -pulumi.export("url", group.ip_address.apply(lambda addr: f"http://{addr.fqdn}:{container_port}")) +pulumi.export("ipAddress", container_group.ip_address.apply(lambda addr: addr.ip)) +pulumi.export("hostname", container_group.ip_address.apply(lambda addr: addr.fqdn)) +pulumi.export("url", container_group.ip_address.apply(lambda addr: f"http://{addr.fqdn}:{container_port}")) diff --git a/container-azure-python/app/app.py b/container-azure-python/app/app.py index f34ca6f98..161faf4d7 100644 --- a/container-azure-python/app/app.py +++ b/container-azure-python/app/app.py @@ -4,4 +4,4 @@ @app.route("/") def index(): - return "Hi, world!" + return "Hello, world! πŸ‘‹" diff --git a/container-azure-typescript/Pulumi.yaml b/container-azure-typescript/Pulumi.yaml index 938093d9d..e6dc0eb10 100644 --- a/container-azure-typescript/Pulumi.yaml +++ b/container-azure-typescript/Pulumi.yaml @@ -14,3 +14,9 @@ template: containerPort: description: The port to expose on the container default: 80 + cpu: + description: The CPU limit of the container instance + default: 1.0 + memory: + description: The memory limit, in GB, of the container instance + default: 1.5 diff --git a/container-azure-typescript/index.ts b/container-azure-typescript/index.ts index 5b3f04762..4f910a8da 100644 --- a/container-azure-typescript/index.ts +++ b/container-azure-typescript/index.ts @@ -42,7 +42,12 @@ const image = new docker.Image("image", { }, }); -const group = new containerinstance.ContainerGroup("group", { +const dnsName = new random.RandomString("dns-name", { + length: 8, + special: false, +}).result.apply(result => `${imageName}-${result.toLowerCase()}`); + +const containerGroup = new containerinstance.ContainerGroup("container-group", { resourceGroupName: resourceGroup.name, osType: "linux", restartPolicy: "always", @@ -79,7 +84,7 @@ const group = new containerinstance.ContainerGroup("group", { ], ipAddress: { type: containerinstance.ContainerGroupIpAddressType.Public, - dnsNameLabel: new random.RandomPet("host", { length: 2 }).id, + dnsNameLabel: dnsName, ports: [ { port: containerPort, @@ -89,6 +94,6 @@ const group = new containerinstance.ContainerGroup("group", { }, }); -export const ipAddress = group.ipAddress.apply(address => address!.ip!); -export const hostname = group.ipAddress.apply(address => address!.fqdn!); -export const url = group.ipAddress.apply(address => `http://${address!.fqdn!}:${containerPort}`); +export const ipAddress = containerGroup.ipAddress.apply(addr => addr!.ip!); +export const hostname = containerGroup.ipAddress.apply(addr => addr!.fqdn!); +export const url = containerGroup.ipAddress.apply(addr => `http://${addr!.fqdn!}:${containerPort}`); From 6d40e76d87e3823657cdad6dccbf6264c7618084 Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Fri, 14 Oct 2022 17:09:18 -0700 Subject: [PATCH 3/9] Tweak resource names --- container-azure-csharp/Program.cs | 2 +- container-azure-python/__main__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/container-azure-csharp/Program.cs b/container-azure-csharp/Program.cs index 499c74e3a..d4694101a 100644 --- a/container-azure-csharp/Program.cs +++ b/container-azure-csharp/Program.cs @@ -14,7 +14,7 @@ var cpu = Math.Max(config.GetObject("cpu"), 1.0); var memory = Math.Max(config.GetObject("memory"), 1.5); - var resourceGroup = new AzureNative.Resources.ResourceGroup("resourceGroup"); + var resourceGroup = new AzureNative.Resources.ResourceGroup("resource-group"); var registry = new AzureNative.ContainerRegistry.Registry("registry", new() { diff --git a/container-azure-python/__main__.py b/container-azure-python/__main__.py index ff67b9bac..543d74518 100644 --- a/container-azure-python/__main__.py +++ b/container-azure-python/__main__.py @@ -10,7 +10,7 @@ cpu = config.get_float("cpu", 1.0) memory = config.get_float("memory", 1.5) -resource_group = resources.ResourceGroup('resource_group') +resource_group = resources.ResourceGroup("resource-group") registry = containerregistry.Registry("registry", containerregistry.RegistryArgs( resource_group_name=resource_group.name, From 754dd2c0723c5e848fe39f7fb6be4bb1636ca002 Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Mon, 17 Oct 2022 16:18:47 -0700 Subject: [PATCH 4/9] Return JSON in all apps, add comments --- container-azure-csharp/Program.cs | 11 +- container-azure-csharp/app/Dockerfile | 4 +- container-azure-csharp/app/Program.cs | 8 +- container-azure-go/app/Dockerfile | 3 +- container-azure-go/app/main.go | 17 ++- container-azure-go/main.go | 13 ++- container-azure-python/__main__.py | 135 +++++++++++++--------- container-azure-python/app/Dockerfile | 3 +- container-azure-python/app/app.py | 2 +- container-azure-typescript/app/Dockerfile | 2 +- container-azure-typescript/app/index.js | 8 +- container-azure-typescript/index.ts | 10 +- 12 files changed, 141 insertions(+), 75 deletions(-) diff --git a/container-azure-csharp/Program.cs b/container-azure-csharp/Program.cs index d4694101a..b9cac4b7c 100644 --- a/container-azure-csharp/Program.cs +++ b/container-azure-csharp/Program.cs @@ -7,6 +7,7 @@ return await Pulumi.Deployment.RunAsync(() => { + // Import the program's configuration settings. var config = new Config(); var appPath = config.Get("appPath") ?? "./app"; var imageName = config.Get("imageName") ?? "my-app"; @@ -14,8 +15,10 @@ var cpu = Math.Max(config.GetObject("cpu"), 1.0); var memory = Math.Max(config.GetObject("memory"), 1.5); + // Create a resource group for the container registry. var resourceGroup = new AzureNative.Resources.ResourceGroup("resource-group"); + // Create a container registry. var registry = new AzureNative.ContainerRegistry.Registry("registry", new() { ResourceGroupName = resourceGroup.Name, @@ -25,15 +28,16 @@ }, }); + // Fetch login credentials for the registry. var credentials = AzureNative.ContainerRegistry.ListRegistryCredentials.Invoke(new() { ResourceGroupName = resourceGroup.Name, RegistryName = registry.Name, }); - var registryUsername = credentials.Apply(result => result.Username!); var registryPassword = credentials.Apply(result => result.Passwords[0]!.Value!); + // Create a container image for the service. var image = new Docker.Image("image", new() { ImageName = Pulumi.Output.Format($"{registry.LoginServer}/{imageName}"), @@ -47,12 +51,14 @@ }, }); + // Use a random string to give the service a unique DNS name. var dnsName = new Random.RandomString("dns-name", new() { Length = 8, Special = false, }).Result.Apply(result => $"{imageName}-{result.ToLower()}"); + // Create a container group for the service that makes it publicly accessible. var containerGroup = new AzureNative.ContainerInstance.ContainerGroup("container-group", new() { ResourceGroupName = resourceGroup.Name, @@ -103,10 +109,11 @@ } }); + // Export the service's IP address, hostname, and fully-qualified URL. return new Dictionary { - ["ipAddress"] = containerGroup.IpAddress.Apply(addr => addr!.Ip), ["hostname"] = containerGroup.IpAddress.Apply(addr => addr!.Fqdn), + ["ip"] = containerGroup.IpAddress.Apply(addr => addr!.Ip), ["url"] = containerGroup.IpAddress.Apply(addr => $"http://{addr!.Fqdn}:{containerPort}"), }; }); diff --git a/container-azure-csharp/app/Dockerfile b/container-azure-csharp/app/Dockerfile index fa18e125c..f1b8147d2 100644 --- a/container-azure-csharp/app/Dockerfile +++ b/container-azure-csharp/app/Dockerfile @@ -4,10 +4,12 @@ WORKDIR /app COPY *.csproj ./ RUN dotnet restore -COPY . ./ +COPY . . RUN dotnet publish -c Release -o out FROM mcr.microsoft.com/dotnet/aspnet:6.0 as base WORKDIR /app + COPY --from=build /app/out . + ENTRYPOINT ["dotnet", "App.dll"] diff --git a/container-azure-csharp/app/Program.cs b/container-azure-csharp/app/Program.cs index 04ce7f50d..3936e7bec 100644 --- a/container-azure-csharp/app/Program.cs +++ b/container-azure-csharp/app/Program.cs @@ -1,6 +1,12 @@ var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); -app.MapGet("/", () => "Hello, world! πŸ‘‹"); +app.MapGet("/", async (context) => +{ + await context.Response.WriteAsJsonAsync(new + { + message = "Hello, world! πŸ‘‹" + }); +}); app.Run(); diff --git a/container-azure-go/app/Dockerfile b/container-azure-go/app/Dockerfile index 9369b67c4..9ed7d590c 100644 --- a/container-azure-go/app/Dockerfile +++ b/container-azure-go/app/Dockerfile @@ -1,5 +1,4 @@ FROM golang - WORKDIR /usr/src/app COPY go.* ./ @@ -8,4 +7,4 @@ RUN go mod download COPY . . RUN go build -o /app -ENTRYPOINT /app +ENTRYPOINT ["/app"] diff --git a/container-azure-go/app/main.go b/container-azure-go/app/main.go index 710b0f0d1..1426cab70 100644 --- a/container-azure-go/app/main.go +++ b/container-azure-go/app/main.go @@ -1,16 +1,31 @@ package main import ( + "encoding/json" "fmt" "log" "net/http" "os" ) +type AppResponse struct { + Message string `json:"message"` +} + func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "Hello, world! πŸ‘‹") + response := AppResponse{ + Message: "Hello, world! πŸ‘‹", + } + + s, err := json.Marshal(response) + if err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } + + w.Header().Set("Content-Type", "application/json") + fmt.Fprintf(w, string(s)) }) if err := http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("PORT")), nil); err != nil { diff --git a/container-azure-go/main.go b/container-azure-go/main.go index 04c9e4e21..1ea3148c0 100644 --- a/container-azure-go/main.go +++ b/container-azure-go/main.go @@ -16,6 +16,7 @@ import ( func main() { pulumi.Run(func(ctx *pulumi.Context) error { + // Import the program's configuration settings. cfg := config.New(ctx, "") imageName := "my-app" if param := cfg.Get("imageName"); param != "" { @@ -33,16 +34,18 @@ func main() { if param := cfg.GetFloat64("cpu"); param != 0 { cpu = param } - memory := 1.0 + memory := 1.5 if param := cfg.GetFloat64("memory"); param != 0 { memory = param } + // Create a resource group for the container registry. resourceGroup, err := resources.NewResourceGroup(ctx, "resource-group", nil) if err != nil { return err } + // Create a container registry. registry, err := containerregistry.NewRegistry(ctx, "registry", &containerregistry.RegistryArgs{ ResourceGroupName: resourceGroup.Name, AdminUserEnabled: pulumi.Bool(true), @@ -54,6 +57,7 @@ func main() { return err } + // Fetch login credentials for the registry. credentials := containerregistry.ListRegistryCredentialsOutput(ctx, containerregistry.ListRegistryCredentialsOutputArgs{ ResourceGroupName: resourceGroup.Name, RegistryName: registry.Name, @@ -61,6 +65,7 @@ func main() { registryUsername := credentials.Username().Elem() registryPassword := credentials.Passwords().Index(pulumi.Int(0)).Value().Elem() + // Create a container image for the service. image, err := docker.NewImage(ctx, "image", &docker.ImageArgs{ ImageName: pulumi.Sprintf("%s/%s", registry.LoginServer, imageName), Build: docker.DockerBuildArgs{ @@ -76,6 +81,7 @@ func main() { return err } + // Use a random string to give the service a unique DNS name. dnsNameSuffix, err := random.NewRandomString(ctx, "dns-name-suffix", &random.RandomStringArgs{ Length: pulumi.Int(8), Special: pulumi.Bool(false), @@ -83,11 +89,11 @@ func main() { if err != nil { return err } - dnsName := dnsNameSuffix.Result.ApplyT(func(result string) string { return fmt.Sprintf("%s-%s", imageName, strings.ToLower(result)) }).(pulumi.StringOutput) + // Create a container group for the service that makes it publicly accessible. containerGroup, err := containerinstance.NewContainerGroup(ctx, "container-group", &containerinstance.ContainerGroupArgs{ ResourceGroupName: resourceGroup.Name, OsType: pulumi.String("linux"), @@ -135,7 +141,8 @@ func main() { }, }) - ctx.Export("ipAddress", containerGroup.IpAddress.Elem().Ip()) + // Export the service's IP address, hostname, and fully-qualified URL. + ctx.Export("ip", containerGroup.IpAddress.Elem().Ip()) ctx.Export("hostname", containerGroup.IpAddress.Elem().Fqdn()) ctx.Export("url", pulumi.Sprintf("http://%s:%d", containerGroup.IpAddress.Elem().Fqdn(), containerPort)) diff --git a/container-azure-python/__main__.py b/container-azure-python/__main__.py index 543d74518..b0c17e447 100644 --- a/container-azure-python/__main__.py +++ b/container-azure-python/__main__.py @@ -3,6 +3,7 @@ import pulumi_random as random from pulumi_azure_native import resources, containerregistry, containerinstance +# Import the program's configuration settings. config = pulumi.Config() image_name = config.get("imageName", "my-app") app_path = config.get("appPath", "./app") @@ -10,16 +11,22 @@ cpu = config.get_float("cpu", 1.0) memory = config.get_float("memory", 1.5) +# Create a resource group for the container registry. resource_group = resources.ResourceGroup("resource-group") -registry = containerregistry.Registry("registry", containerregistry.RegistryArgs( - resource_group_name=resource_group.name, - admin_user_enabled=True, - sku=containerregistry.SkuArgs( - name=containerregistry.SkuName.BASIC, +# Create a container registry. +registry = containerregistry.Registry( + "registry", + containerregistry.RegistryArgs( + resource_group_name=resource_group.name, + admin_user_enabled=True, + sku=containerregistry.SkuArgs( + name=containerregistry.SkuName.BASIC, + ), ), -)) +) +# Fetch login credentials for the registry. credentials = containerregistry.list_registry_credentials_output( resource_group_name=resource_group.name, registry_name=registry.name, @@ -28,7 +35,9 @@ registry_username = credentials.apply(lambda creds: creds.username) registry_password = credentials.apply(lambda creds: creds.passwords[0].value) -image = docker.Image("image", +# Create a container image for the service. +image = docker.Image( + "image", image_name=pulumi.Output.concat(registry.login_server, "/", image_name), build=docker.DockerBuild( context=app_path, @@ -40,62 +49,76 @@ ), ) -dns_name = random.RandomString("dns-name", random.RandomStringArgs( - length=8, - special=False, -)).result.apply(lambda result: f"{image_name}-{result.lower()}") +# Use a random string to give the service a unique DNS name. +dns_name = random.RandomString( + "dns-name", + random.RandomStringArgs( + length=8, + special=False, + ), +).result.apply(lambda result: f"{image_name}-{result.lower()}") -container_group = containerinstance.ContainerGroup("container-group", containerinstance.ContainerGroupArgs( - resource_group_name=resource_group.name, - os_type="linux", - restart_policy="always", - image_registry_credentials=[ - containerinstance.ImageRegistryCredentialArgs( - server=registry.login_server, - username=registry_username, - password=registry_password, - ), - ], - containers=[ - containerinstance.ContainerArgs( - name=image_name, - image=image.image_name, +# Create a container group for the service that makes it publicly accessible. +container_group = containerinstance.ContainerGroup( + "container-group", + containerinstance.ContainerGroupArgs( + resource_group_name=resource_group.name, + os_type="linux", + restart_policy="always", + image_registry_credentials=[ + containerinstance.ImageRegistryCredentialArgs( + server=registry.login_server, + username=registry_username, + password=registry_password, + ), + ], + containers=[ + containerinstance.ContainerArgs( + name=image_name, + image=image.image_name, + ports=[ + containerinstance.ContainerPortArgs( + port=container_port, + protocol="tcp", + ), + ], + environment_variables=[ + containerinstance.EnvironmentVariableArgs( + name="FLASK_RUN_PORT", + value=str(container_port), + ), + containerinstance.EnvironmentVariableArgs( + name="FLASK_RUN_HOST", + value="0.0.0.0", + ), + ], + resources=containerinstance.ResourceRequirementsArgs( + requests=containerinstance.ResourceRequestsArgs( + cpu=cpu, + memory_in_gb=memory, + ), + ), + ), + ], + ip_address=containerinstance.IpAddressArgs( + type=containerinstance.ContainerGroupIpAddressType.PUBLIC, + dns_name_label=dns_name, ports=[ - containerinstance.ContainerPortArgs( + containerinstance.PortArgs( port=container_port, protocol="tcp", ), ], - environment_variables=[ - containerinstance.EnvironmentVariableArgs( - name="FLASK_RUN_PORT", - value=str(container_port), - ), - containerinstance.EnvironmentVariableArgs( - name="FLASK_RUN_HOST", - value="0.0.0.0", - ), - ], - resources=containerinstance.ResourceRequirementsArgs( - requests=containerinstance.ResourceRequestsArgs( - cpu=cpu, - memory_in_gb=memory, - ), - ), ), - ], - ip_address=containerinstance.IpAddressArgs( - type=containerinstance.ContainerGroupIpAddressType.PUBLIC, - dns_name_label=dns_name, - ports=[ - containerinstance.PortArgs( - port=container_port, - protocol="tcp", - ), - ], ), -)) +) -pulumi.export("ipAddress", container_group.ip_address.apply(lambda addr: addr.ip)) +# Export the service's IP address, hostname, and fully-qualified URL. pulumi.export("hostname", container_group.ip_address.apply(lambda addr: addr.fqdn)) -pulumi.export("url", container_group.ip_address.apply(lambda addr: f"http://{addr.fqdn}:{container_port}")) +pulumi.export("ip", container_group.ip_address.apply(lambda addr: addr.ip)) +pulumi.export( + "url", + container_group.ip_address.apply( + lambda addr: f"http://{addr.fqdn}:{container_port}" + ), +) diff --git a/container-azure-python/app/Dockerfile b/container-azure-python/app/Dockerfile index 1e2f05ac2..2b2d4db60 100644 --- a/container-azure-python/app/Dockerfile +++ b/container-azure-python/app/Dockerfile @@ -1,8 +1,9 @@ FROM python:3.10-alpine WORKDIR /usr/src/app -COPY requirements.txt requirements.txt +COPY requirements.txt ./ RUN pip install -r requirements.txt + COPY . . CMD ["flask", "run"] diff --git a/container-azure-python/app/app.py b/container-azure-python/app/app.py index 161faf4d7..aec19bd2d 100644 --- a/container-azure-python/app/app.py +++ b/container-azure-python/app/app.py @@ -4,4 +4,4 @@ @app.route("/") def index(): - return "Hello, world! πŸ‘‹" + return { "message": "Hello, world! πŸ‘‹" } diff --git a/container-azure-typescript/app/Dockerfile b/container-azure-typescript/app/Dockerfile index d35a7bcf9..1d41c7e42 100644 --- a/container-azure-typescript/app/Dockerfile +++ b/container-azure-typescript/app/Dockerfile @@ -1,9 +1,9 @@ FROM node:16 - WORKDIR /usr/src/app COPY package*.json ./ RUN npm install + COPY . . CMD [ "node", "index.js" ] diff --git a/container-azure-typescript/app/index.js b/container-azure-typescript/app/index.js index 1778c60f3..389b064c1 100644 --- a/container-azure-typescript/app/index.js +++ b/container-azure-typescript/app/index.js @@ -4,12 +4,10 @@ const express = require("express"); const app = express(); app.get("/", (req, res) => { - res.send("Hello, world! πŸ‘‹"); + res.json({ message: "Hello, world! πŸ‘‹" }); }); -const host = "0.0.0.0"; const port = process.env.PORT; - -app.listen(port, host, () => { - console.log(`Running on http://${host}:${port}`); +app.listen(port, () => { + console.log(`Listening on port ${port}`); }); diff --git a/container-azure-typescript/index.ts b/container-azure-typescript/index.ts index 4f910a8da..84d5407bb 100644 --- a/container-azure-typescript/index.ts +++ b/container-azure-typescript/index.ts @@ -5,13 +5,16 @@ import * as containerinstance from "@pulumi/azure-native/containerinstance"; import * as random from "@pulumi/random"; import * as docker from "@pulumi/docker"; +// Import the program's configuration settings. const config = new pulumi.Config(); const imageName = config.get("imageName") || "my-app"; const appPath = config.get("appPath") || "./app"; const containerPort = config.getNumber("containerPort") || 80; +// Create a resource group for the container registry. const resourceGroup = new resources.ResourceGroup("resource-group"); +// Create a container registry. const registry = new containerregistry.Registry("registry", { resourceGroupName: resourceGroup.name, adminUserEnabled: true, @@ -20,6 +23,7 @@ const registry = new containerregistry.Registry("registry", { }, }); +// Fetch login credentials for the registry. const credentials = containerregistry.listRegistryCredentialsOutput({ resourceGroupName: resourceGroup.name, registryName: registry.name, @@ -30,6 +34,7 @@ const credentials = containerregistry.listRegistryCredentialsOutput({ }; }); +// Create a container image for the service. const image = new docker.Image("image", { imageName: pulumi.interpolate`${registry.loginServer}/${imageName}`, build: { @@ -42,11 +47,13 @@ const image = new docker.Image("image", { }, }); +// Use a random string to give the service a unique DNS name. const dnsName = new random.RandomString("dns-name", { length: 8, special: false, }).result.apply(result => `${imageName}-${result.toLowerCase()}`); +// Create a container group for the service that makes it publicly accessible. const containerGroup = new containerinstance.ContainerGroup("container-group", { resourceGroupName: resourceGroup.name, osType: "linux", @@ -94,6 +101,7 @@ const containerGroup = new containerinstance.ContainerGroup("container-group", { }, }); -export const ipAddress = containerGroup.ipAddress.apply(addr => addr!.ip!); +// Export the service's IP address, hostname, and fully-qualified URL. export const hostname = containerGroup.ipAddress.apply(addr => addr!.fqdn!); +export const ip = containerGroup.ipAddress.apply(addr => addr!.ip!); export const url = containerGroup.ipAddress.apply(addr => `http://${addr!.fqdn!}:${containerPort}`); From 194cbefe0671d4ca974ce9df5eda9ecf481ea339 Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Tue, 18 Oct 2022 13:35:05 -0700 Subject: [PATCH 5/9] Add metadata --- metadata/groups/container-service-azure.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 metadata/groups/container-service-azure.yaml diff --git a/metadata/groups/container-service-azure.yaml b/metadata/groups/container-service-azure.yaml new file mode 100644 index 000000000..d1704a47b --- /dev/null +++ b/metadata/groups/container-service-azure.yaml @@ -0,0 +1,11 @@ +name: Container Service on Azure +kind: architecture +parent: container-service +slug: azure +clouds: + - azure +templates: + - container-azure-typescript + - container-azure-python + - container-azure-go + - container-azure-csharp From f63cc3e1bcc86cfa7ec2334e8dbbff502c798edd Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Thu, 20 Oct 2022 11:10:15 -0700 Subject: [PATCH 6/9] Make CPU and memory configurable in the TS template --- container-azure-go/main.go | 8 ++++---- container-azure-python/__main__.py | 2 +- container-azure-typescript/index.ts | 8 +++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/container-azure-go/main.go b/container-azure-go/main.go index 1ea3148c0..656c76896 100644 --- a/container-azure-go/main.go +++ b/container-azure-go/main.go @@ -18,14 +18,14 @@ func main() { // Import the program's configuration settings. cfg := config.New(ctx, "") - imageName := "my-app" - if param := cfg.Get("imageName"); param != "" { - imageName = param - } appPath := "./app" if param := cfg.Get("appPath"); param != "" { appPath = param } + imageName := "my-app" + if param := cfg.Get("imageName"); param != "" { + imageName = param + } containerPort := 80 if param := cfg.GetInt("containerPort"); param != 0 { containerPort = param diff --git a/container-azure-python/__main__.py b/container-azure-python/__main__.py index b0c17e447..6e4e3cdde 100644 --- a/container-azure-python/__main__.py +++ b/container-azure-python/__main__.py @@ -5,8 +5,8 @@ # Import the program's configuration settings. config = pulumi.Config() -image_name = config.get("imageName", "my-app") app_path = config.get("appPath", "./app") +image_name = config.get("imageName", "my-app") container_port = config.get_int("containerPort", 80) cpu = config.get_float("cpu", 1.0) memory = config.get_float("memory", 1.5) diff --git a/container-azure-typescript/index.ts b/container-azure-typescript/index.ts index 84d5407bb..2fd0bda6d 100644 --- a/container-azure-typescript/index.ts +++ b/container-azure-typescript/index.ts @@ -7,9 +7,11 @@ import * as docker from "@pulumi/docker"; // Import the program's configuration settings. const config = new pulumi.Config(); -const imageName = config.get("imageName") || "my-app"; const appPath = config.get("appPath") || "./app"; +const imageName = config.get("imageName") || "my-app"; const containerPort = config.getNumber("containerPort") || 80; +const cpu = config.getNumber("cpu") || 1.0; +const memory = config.getNumber("memory") || 1.5; // Create a resource group for the container registry. const resourceGroup = new resources.ResourceGroup("resource-group"); @@ -83,8 +85,8 @@ const containerGroup = new containerinstance.ContainerGroup("container-group", { ], resources: { requests: { - cpu: 1.0, - memoryInGB: 1.5, + cpu: cpu, + memoryInGB: memory, }, }, }, From 24d805f511891b2d32fd5ff89c928d81a9a58734 Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Thu, 20 Oct 2022 12:03:55 -0700 Subject: [PATCH 7/9] Use 1 and 2 as defaults for CPU and memory --- container-azure-csharp/Program.cs | 4 ++-- container-azure-csharp/Pulumi.yaml | 8 ++++---- container-azure-go/Pulumi.yaml | 8 ++++---- container-azure-go/main.go | 8 ++++---- container-azure-python/Pulumi.yaml | 8 ++++---- container-azure-python/__main__.py | 4 ++-- container-azure-typescript/Pulumi.yaml | 8 ++++---- container-azure-typescript/index.ts | 4 ++-- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/container-azure-csharp/Program.cs b/container-azure-csharp/Program.cs index b9cac4b7c..83d91786a 100644 --- a/container-azure-csharp/Program.cs +++ b/container-azure-csharp/Program.cs @@ -12,8 +12,8 @@ var appPath = config.Get("appPath") ?? "./app"; var imageName = config.Get("imageName") ?? "my-app"; var containerPort = config.GetInt32("containerPort") ?? 80; - var cpu = Math.Max(config.GetObject("cpu"), 1.0); - var memory = Math.Max(config.GetObject("memory"), 1.5); + var cpu = config.GetInt32("cpu") ?? 1; + var memory = config.GetInt32("memory") ?? 2; // Create a resource group for the container registry. var resourceGroup = new AzureNative.Resources.ResourceGroup("resource-group"); diff --git a/container-azure-csharp/Pulumi.yaml b/container-azure-csharp/Pulumi.yaml index 80b641c0e..a4959b38a 100644 --- a/container-azure-csharp/Pulumi.yaml +++ b/container-azure-csharp/Pulumi.yaml @@ -14,8 +14,8 @@ template: description: The port to expose on the container default: 80 cpu: - description: The CPU limit of the container instance - default: 1.0 + description: The number of CPU cores to allocate on the container + default: 1 memory: - description: The memory limit, in GB, of the container instance - default: 1.5 + description: The amount of memory, in GB, to allocate on the container + default: 2 diff --git a/container-azure-go/Pulumi.yaml b/container-azure-go/Pulumi.yaml index 22538c61f..a348925f8 100644 --- a/container-azure-go/Pulumi.yaml +++ b/container-azure-go/Pulumi.yaml @@ -14,8 +14,8 @@ template: description: The port to expose on the container default: 80 cpu: - description: The CPU limit of the container instance - default: 1.0 + description: The number of CPU cores to allocate on the container + default: 1 memory: - description: The memory limit, in GB, of the container instance - default: 1.5 + description: The amount of memory, in GB, to allocate on the container + default: 2 diff --git a/container-azure-go/main.go b/container-azure-go/main.go index 656c76896..80c8de2d6 100644 --- a/container-azure-go/main.go +++ b/container-azure-go/main.go @@ -30,12 +30,12 @@ func main() { if param := cfg.GetInt("containerPort"); param != 0 { containerPort = param } - cpu := 1.0 - if param := cfg.GetFloat64("cpu"); param != 0 { + cpu := 1 + if param := cfg.GetInt("cpu"); param != 0 { cpu = param } - memory := 1.5 - if param := cfg.GetFloat64("memory"); param != 0 { + memory := 2 + if param := cfg.GetInt("memory"); param != 0 { memory = param } diff --git a/container-azure-python/Pulumi.yaml b/container-azure-python/Pulumi.yaml index 0045be142..4352fc81f 100644 --- a/container-azure-python/Pulumi.yaml +++ b/container-azure-python/Pulumi.yaml @@ -17,8 +17,8 @@ template: description: The port to expose on the container default: 80 cpu: - description: The CPU limit of the container instance - default: 1.0 + description: The number of CPU cores to allocate on the container + default: 1 memory: - description: The memory limit, in GB, of the container instance - default: 1.5 + description: The amount of memory, in GB, to allocate on the container + default: 2 diff --git a/container-azure-python/__main__.py b/container-azure-python/__main__.py index 6e4e3cdde..e8322917a 100644 --- a/container-azure-python/__main__.py +++ b/container-azure-python/__main__.py @@ -8,8 +8,8 @@ app_path = config.get("appPath", "./app") image_name = config.get("imageName", "my-app") container_port = config.get_int("containerPort", 80) -cpu = config.get_float("cpu", 1.0) -memory = config.get_float("memory", 1.5) +cpu = config.get_int("cpu", 1) +memory = config.get_int("memory", 2) # Create a resource group for the container registry. resource_group = resources.ResourceGroup("resource-group") diff --git a/container-azure-typescript/Pulumi.yaml b/container-azure-typescript/Pulumi.yaml index e6dc0eb10..a46b063fc 100644 --- a/container-azure-typescript/Pulumi.yaml +++ b/container-azure-typescript/Pulumi.yaml @@ -15,8 +15,8 @@ template: description: The port to expose on the container default: 80 cpu: - description: The CPU limit of the container instance - default: 1.0 + description: The number of CPU cores to allocate on the container + default: 1 memory: - description: The memory limit, in GB, of the container instance - default: 1.5 + description: The amount of memory, in GB, to allocate on the container + default: 2 diff --git a/container-azure-typescript/index.ts b/container-azure-typescript/index.ts index 2fd0bda6d..044baa200 100644 --- a/container-azure-typescript/index.ts +++ b/container-azure-typescript/index.ts @@ -10,8 +10,8 @@ const config = new pulumi.Config(); const appPath = config.get("appPath") || "./app"; const imageName = config.get("imageName") || "my-app"; const containerPort = config.getNumber("containerPort") || 80; -const cpu = config.getNumber("cpu") || 1.0; -const memory = config.getNumber("memory") || 1.5; +const cpu = config.getNumber("cpu") || 1; +const memory = config.getNumber("memory") || 2; // Create a resource group for the container registry. const resourceGroup = new resources.ResourceGroup("resource-group"); From 4a593de389895fdb0258ad32aa1f40e669c118be Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Thu, 20 Oct 2022 12:53:34 -0700 Subject: [PATCH 8/9] Make image tag configurable, templatize package.json --- container-azure-csharp/Program.cs | 3 ++- container-azure-go/main.go | 6 +++++- container-azure-python/__main__.py | 3 ++- container-azure-typescript/index.ts | 3 ++- container-azure-typescript/package.json | 3 +-- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/container-azure-csharp/Program.cs b/container-azure-csharp/Program.cs index 83d91786a..acb7c31fa 100644 --- a/container-azure-csharp/Program.cs +++ b/container-azure-csharp/Program.cs @@ -11,6 +11,7 @@ var config = new Config(); var appPath = config.Get("appPath") ?? "./app"; var imageName = config.Get("imageName") ?? "my-app"; + var imageTag = config.Get("imageTag") ?? "latest"; var containerPort = config.GetInt32("containerPort") ?? 80; var cpu = config.GetInt32("cpu") ?? 1; var memory = config.GetInt32("memory") ?? 2; @@ -40,7 +41,7 @@ // Create a container image for the service. var image = new Docker.Image("image", new() { - ImageName = Pulumi.Output.Format($"{registry.LoginServer}/{imageName}"), + ImageName = Pulumi.Output.Format($"{registry.LoginServer}/{imageName}:{imageTag}"), Build = new Docker.DockerBuild { Context = appPath, }, diff --git a/container-azure-go/main.go b/container-azure-go/main.go index 80c8de2d6..13d53f7af 100644 --- a/container-azure-go/main.go +++ b/container-azure-go/main.go @@ -26,6 +26,10 @@ func main() { if param := cfg.Get("imageName"); param != "" { imageName = param } + imageTag := "latest" + if param := cfg.Get("imageTag"); param != "" { + imageName = param + } containerPort := 80 if param := cfg.GetInt("containerPort"); param != 0 { containerPort = param @@ -67,7 +71,7 @@ func main() { // Create a container image for the service. image, err := docker.NewImage(ctx, "image", &docker.ImageArgs{ - ImageName: pulumi.Sprintf("%s/%s", registry.LoginServer, imageName), + ImageName: pulumi.Sprintf("%s/%s:%s", registry.LoginServer, imageName, imageTag), Build: docker.DockerBuildArgs{ Context: pulumi.String(appPath), }, diff --git a/container-azure-python/__main__.py b/container-azure-python/__main__.py index e8322917a..7547bfd3f 100644 --- a/container-azure-python/__main__.py +++ b/container-azure-python/__main__.py @@ -7,6 +7,7 @@ config = pulumi.Config() app_path = config.get("appPath", "./app") image_name = config.get("imageName", "my-app") +image_tag = config.get("imageTag", "latest") container_port = config.get_int("containerPort", 80) cpu = config.get_int("cpu", 1) memory = config.get_int("memory", 2) @@ -38,7 +39,7 @@ # Create a container image for the service. image = docker.Image( "image", - image_name=pulumi.Output.concat(registry.login_server, "/", image_name), + image_name=pulumi.Output.concat(registry.login_server, f"/{image_name}:{image_tag}"), build=docker.DockerBuild( context=app_path, ), diff --git a/container-azure-typescript/index.ts b/container-azure-typescript/index.ts index 044baa200..cc71fba1d 100644 --- a/container-azure-typescript/index.ts +++ b/container-azure-typescript/index.ts @@ -9,6 +9,7 @@ import * as docker from "@pulumi/docker"; const config = new pulumi.Config(); const appPath = config.get("appPath") || "./app"; const imageName = config.get("imageName") || "my-app"; +const imageTag = config.get("imageTag") || "latest"; const containerPort = config.getNumber("containerPort") || 80; const cpu = config.getNumber("cpu") || 1; const memory = config.getNumber("memory") || 2; @@ -38,7 +39,7 @@ const credentials = containerregistry.listRegistryCredentialsOutput({ // Create a container image for the service. const image = new docker.Image("image", { - imageName: pulumi.interpolate`${registry.loginServer}/${imageName}`, + imageName: pulumi.interpolate`${registry.loginServer}/${imageName}:${imageTag}`, build: { context: appPath, }, diff --git a/container-azure-typescript/package.json b/container-azure-typescript/package.json index 3ed6fe908..ec4ad0690 100644 --- a/container-azure-typescript/package.json +++ b/container-azure-typescript/package.json @@ -1,6 +1,5 @@ { - "name": "azure-container", - "main": "index.ts", + "name": "${PROJECT}", "devDependencies": { "@types/node": "^14" }, From 2c0f8306bde5f89b008de6ee7d127c3803b52ce1 Mon Sep 17 00:00:00 2001 From: Christian Nunciato Date: Thu, 20 Oct 2022 17:37:04 -0700 Subject: [PATCH 9/9] =?UTF-8?q?Drop=20emojis=20from=20responses=20?= =?UTF-8?q?=F0=9F=98=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- container-azure-csharp/app/Program.cs | 2 +- container-azure-go/app/main.go | 6 +++--- container-azure-python/app/app.py | 2 +- container-azure-typescript/app/index.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/container-azure-csharp/app/Program.cs b/container-azure-csharp/app/Program.cs index 3936e7bec..24b5f3422 100644 --- a/container-azure-csharp/app/Program.cs +++ b/container-azure-csharp/app/Program.cs @@ -5,7 +5,7 @@ { await context.Response.WriteAsJsonAsync(new { - message = "Hello, world! πŸ‘‹" + message = "Hello, world!" }); }); diff --git a/container-azure-go/app/main.go b/container-azure-go/app/main.go index 1426cab70..586ae4b82 100644 --- a/container-azure-go/app/main.go +++ b/container-azure-go/app/main.go @@ -16,16 +16,16 @@ func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { response := AppResponse{ - Message: "Hello, world! πŸ‘‹", + Message: "Hello, world!", } - s, err := json.Marshal(response) + body, err := json.Marshal(response) if err != nil { http.Error(w, "Internal Server Error", http.StatusInternalServerError) } w.Header().Set("Content-Type", "application/json") - fmt.Fprintf(w, string(s)) + fmt.Fprint(w, string(body)) }) if err := http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("PORT")), nil); err != nil { diff --git a/container-azure-python/app/app.py b/container-azure-python/app/app.py index aec19bd2d..64a0c1dd4 100644 --- a/container-azure-python/app/app.py +++ b/container-azure-python/app/app.py @@ -4,4 +4,4 @@ @app.route("/") def index(): - return { "message": "Hello, world! πŸ‘‹" } + return { "message": "Hello, world!" } diff --git a/container-azure-typescript/app/index.js b/container-azure-typescript/app/index.js index 389b064c1..ccf779d1e 100644 --- a/container-azure-typescript/app/index.js +++ b/container-azure-typescript/app/index.js @@ -4,7 +4,7 @@ const express = require("express"); const app = express(); app.get("/", (req, res) => { - res.json({ message: "Hello, world! πŸ‘‹" }); + res.json({ message: "Hello, world!" }); }); const port = process.env.PORT;