Azure Multi-Container YAML

21 October 2025

Background

As an exercise I had run WordPress via a Docker Compose file locally and then within Azure (I would not recommend this for “production” systems, this was merely an intellectual exercise and I based my ideas on this article amongst other.

Running containers within Azure is a little confusing for the beginner as, typical for Microsoft, there are many ways to do the same thing and I noted that it is possible to run multiple containers with a YAML file as opposed to a Docker Compose file.

So I created a YAML file which mirrored my Compose file and tried to run it

az container create --resource-group mygroup --dns-name-label myyaml  --file deploy-wp.yaml

With a YAML file:

apiVersion: 2021-09-01
location: uksouth
name: wordpress-group
type: Microsoft.ContainerInstance/containerGroups
properties:
containers:
- name: wordpress
properties:
image: wordpress:6.4
resources:
requests:
cpu: 1
memoryInGb: 1.5
ports:
- port: 80
environmentVariables:
- name: WORDPRESS_DB_HOST
value: db
- name: WORDPRESS_DB_USER
value: wordpressuser
- name: WORDPRESS_DB_PASSWORD
value: wordpresspass
- name: WORDPRESS_DB_NAME
value: wordpressdb
- name: mysql
properties:

image: mysql:8.0.27
resources:
requests:
cpu: 1
memoryInGb: 1.5
ports:
- port: 3306
- port: 33060
environmentVariables:
- name: MYSQL_ROOT_PASSWORD
value: rootpass
- name: MYSQL_DATABASE
value: wordpressdb
- name: MYSQL_USER
value: wordpressuser
- name: MYSQL_PASSWORD
value: wordpresspass
osType: Linux
ipAddress:
type: Public
dnsNameLabel: testwordpress
ports:
- protocol: tcp
port: 80
- protocol: tcp
port: 3306
- protocol: tcp
port: 33060

The containers started and I could read the logs via

az container logs –resource-group mygroup –name wordpress-group –container-name wordpress
az container logs –resource-group mygroup –name wordpress-group –container-name mysql

I could also get the FQDN of wordpress via

az container show --resource-group mygroup --name wordpress-group  --query "{FQDN:ipAddress.fqdn,ProvisioningState:provisioningState}" --out table

The Problem

I then browsed to the port 80 endpoint for the WordPress container (URL obtained from the Azure portal) and….Error….wordpress could not connect to the database

The Solution

After much head scratching and searching I found an article that suggested using 127.0.0.1 for the “db name” in the yaml file

          - name: WORDPRESS_DB_HOST
value: 127.0.0.1:3306

Azure Error For ACI Container

21 October 2025

The Problem

I was trying to run a “simple” hello-world Azure Container Instance. When I typed

az container create --resource-group myrersourcegroup --name mytestcontainer --image "mcr.microsoft.com/azuredocs/aci-helloworld" --dns-name-label mydnslabel --ports 80 443

And it worked.

I tried it again a few days later and I got the error

(InternalServerError) Encountered an internal server error. The tracking activity id is 'ba9613c2-70b8-4e3c-8d51-51e603d1c2c6', correlation id is '7e07cd3a-6e34-4ff6-8dde-8be7e58a6262'.



What was going on?

The Solution

It turns out that this is a DNS label error. As I had copied/pasted the command I was using the DNS name “mydnslabel” and it looks like someone else was using the same label. Changing the DNS label to another name allowed the command and container to work

AutoMapper and “Could not load type ‘SqlGuidCaster'” Error

7 April 2025

Background

I had a VS 2022 solution utilising .NET Core 3. I wanted to upgrade it to .NET Core 9 so I “upgraded” the projects withing the solution and updated the nugets to reflect later versions utilising “9”. So far so good

I ran up the WPF UI – this worked correctly, entities were read from SQL via entity framework and all was good and sunny.

Then I ran my unit tests. All good

Then I ran my integration tests. They failed! But, to be fair, they are fairly noddy tests but at least they tested reading/writing entities to the database to test the sanity and functionality of my code. So I had a problem

The Problem

The error returned from the tests (utilising XUnit) was

System.Reflection.ReflectionTypeLoadException : Unable to load one or more of the requested types.
        /// Could not load type 'SqlGuidCaster' from assembly 'Microsoft.Data.SqlClient, Version=5.0.0.0,

Hmm. I checked my solution. I don’t reference Microsoft.Data.SqlClient. So what was going on?

The Solution

The errant line of code throwing an exception was some initialisation code for Automapper

        public static void ConfigureAutoMapperServices(this IServiceCollection services)
        {
            services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
        }

It would appear that the AppDomain.CurrentDomain.GetAssemblies() was causing the issue. After some searching I found this article and this one. So I think that there is a bug in version 5.x of Microsoft.Data.SqlClient and this is/was causing the issue.

The solution? To explicitly add a nuget for version 6.x.x of Microsoft.Data.SqlClient to the project

OpenVPN on Docker and the Strange Error Message Saga

29 December 2024

Background

A “dockerised” version of openvpn server was running on a linux server and had been running without issue for years (as per these instructions).

The Problem

However, a fresh install of the OpenVPN client on an iPad led to error messages about an insecure hash

You are using insecure hash algorithm in CA signature.
Please regenerate CA with other hash algorithm

After some head-scratching it was realised that the home-generated certificates (CA and others) had an insecure hash algorithm (i.e. obsolete or unsafe). So it was decided to regenerate the certificates. But, firstly (which turns out to have been the mistake) was to do

apt-get upgrade

to ensure that the latest version of openssl etc was installed.

An attempt to use the previous method for certificate generation was used, however, the CA.sh script no longer works. So the certificates were generated by hand (with thanks to these guys). The openvpn server config was updated for the new certificates and the docker container restarted.

The Saga and its Solution

Hmm, the vpn did not appear to work. Had I made an error in the openvpn.conf file whilst during the fix? No, the problem turns out to be a strange issue where the container (which has run for years) was complaining about two things.

Firstly

docker container start -a my-openvpn-container

gave a clue.

Checking IPv6 Forwarding
Sysctl error for default forwarding, please run docker with '--sysctl net.ipv6.conf.default.forwarding=1'
Sysctl error for all forwarding, please run docker with '--sysctl net.ipv6.conf.all.forwarding=1'

This was a new error to me. The original container had been created via a command

docker run -v $PWD/vpn-data:/etc/openvpn -d -p 3000:1194/udp --cap-add=NET_ADMIN myownvpn

So I tried running the container with –sysctl commands:

docker run --sysctl net.ipv6.conf.default.forwarding=1 --sysctl net.ipv6.conf.all.forwarding=1 -v $PWD/vpn-data:/etc/openvpn -p 3000:1194/udp --cap-add=NET_ADMIN myownvpn

This solved the first issue, although it turns out not to be a real issue with the docker run command, the issue appears to be with a docker container run and stop/started prior to my linux apt-get upgrade. As our American cousins say “go figure”. So this ipv6 “issue” appears to be a red herring (but is documented here for completeness)

The second issue (which turns out to be the real issue) was pulled from the openvpn.log (I have a line log-append /etc/openvpn/logs/openvpn.log in the the openvpn.conf). The error message was

ERROR: Cannot open TUN/TAP dev /dev/net/tun:

After some searching I found this page which suggested adding

--device=/dev/net/tun

to the run command

docker run -d --device=/dev/net/tun --sysctl net.ipv6.conf.default.forwarding=1 --sysctl net.ipv6.conf.all.forwarding=1 -v $PWD/vpn-data:/etc/openvpn -p 3000:1194/udp --cap-add=NET_ADMIN myownvpn

And, voila, everything works again.

Conclusion

I have no idea what happened with the linux upgrade but, firstly, obviously something changed that stopped an existing container that had been stop/started many times from running correctly, no idea what/why. Secondly, no idea what changed to necessitate the addition of –device=/dev/net/tun to the docker run command, but this solved the issue.

Docker CLI and Compose Information Message

3 April 2024

From the Docker CLI when using a Docker Context for Azure and you do

docker compose up

You get the following message

Docker Compose's integration for ECS and ACI will be retired in November 2023. Learn more: https://docs.docker.com/go/compose-ecs-eol/

What that means, I think, is that Docker have stopped supported Compose from the Docker CLI. I’m not sure if you can use/is-supported Docker Compose from the azure CLI

Docker Containers and Azure – An Introduction

3 April 2024

The Problem

I wanted to start using Docker Containers on Azure as I had been using them locally for ages and found them very useful. I had progressed to using Docker Compose for multi-container apps and even for single-container apps as the compose-file contained all the information needed to run the container rather than remember port-mappings, volumes etc for the docker run command.

However….the documentation for containers on Azure is confusing. It’s simple to get a container up and running but it’s not so simple to understand what/where/why. Hence this article

more “Docker Containers and Azure – An Introduction”

Serilog in .Net Core 6

25 September 2022

The Problem

I wanted to add Serilog to a WebAPI using .Net Core 6. The “startup” has changed from .Net Core 3 and the “wiring” up of services so it wasn’t clear to me how to get it all working.

The Solution

After some head scratching and searching I work out that you needed from this article and this article (thanks to the authers)

So I created a method

protected void ConfigureLogging(WebApplicationBuilder appBuilder)
{
appBuilder.Host.UseSerilog((ctx, lc) => lc
.ReadFrom.Configuration(ctx.Configuration)
.WriteTo.Console()
);

}

This method is called from the program.cs “startup” code.

Placed the following in appsetttings.json

{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"DRNJ": "Debug",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "@mt = 'An unhandled exception has occurred while executing the request.'"
}
}
],
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "c:\\temp\\log\\apilog-.txt",
"rollingInterval": "Day"
}
}
]
},
"AllowedHosts": "*"
}

 

And, voila, it all worked

 

Serilog And .Net Core 3.1

25 September 2022

The Problem

I found configuring Serilog for .Net Core quite complex and poorly documented. All I wanted to do was to pipe log messages to a text file.

The Solution

After some searching I found this project.

The following code was added to Program.cs

public static void Main(string[] args)
{ 
CreateHostBuilderWithSimpleSerilog(args).Build().Run();
}

public static IHostBuilder CreateHostBuilderWithSimpleSerilog(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((context, builder) =>
{
//----------------------------------------------------------------------
// Simple SeriLog |
// Using https://github.com/serilog/serilog-extensions-logging-file |
//----------------------------------------------------------------------
builder.AddFile(context.Configuration.GetLoggerConfiguration());
})
.ConfigureWebHostDefaults(webBuilder =>
{
if (bool.Parse(Environment.GetEnvironmentVariable("USE_HTTP_SYS") ?? "false"))
{
webBuilder.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
});
}
webBuilder.UseStartup<Startup>();
});

Along with

 public static class StartupConfiguration
    {

        public static IConfigurationSection GetLoggerConfiguration(this IConfiguration config)
        {
            return config.GetSection("Logging");
        }

        public static T Get<T>(this IConfiguration config, string name)
        {
            return config
                 .GetSection(name)
                 .Get<T>();
        }
    }

And then the Appsettings.json section for logging

 

"Logging": {
"OutputTemplate": "{Timestamp:o} {RequestId,13} [{Level:u3}] {Message} Properties: {Properties:j} ({EventId:x8}){NewLine}{Exception}",
"PathFormat": "Logs/MyLog-{Date}.log",
"MinimumLevel": "Information",
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning",
"Microsoft.EntityFrameworkCore": "Warning"
}
}

 

And Voila. Logging to file works and Dependency Injection of Serilog is wired up too.

Raspberry Pi 4 and Ubuntu and SSD

16 November 2021

The Problem

I made the mistake of trying to install Ubuntu on an SSD on an already working Raspberry Pi 4. The device as Raspian on it and was working normally for over six months. However, I was playing with docker and wanted some features not available in Raspbian. Rather than flash an SD Card I thought that I would use a Samsung 840 Pro 500GB SSD that I had lying around.

I followed the instructions from Ubuntu I tried to install Ubuntu Server 21 64Bit. The SSD was written correctly but when I booted the Pi 4 the boot took ages and I got many messages of the type

EXT4-fs error (device nvme0n1p7): ext4_find_entry:1463: inode #525023

on the console. I tried Ubuntu 20 instead, this would not boot. I tried workstation 21 and it showed the same issues as server. So I reverted to Ubuntu 21 server.

Investigation

I searched for P i4 Ubuntu SSD issues and found this article. So at least I was not alone in my problems.

After more searching I found an article that suggested adding

pcie_aspm=force

or

nvme_core.default_ps_max_latency_us=5500

To the grub configuration.

Great…apart from it seems that Ubuntu on a Pi 4 doesn’t seem to use grub (perhaps I am wrong) so I couldn’t update any grub boot configuration.

A bit of searching at turns out that on the Pi you can use “quirks” mode for the USB controller. All you need is the device ID….

Following this article I found out how to get this ID for my USB enclosure.

The Solution

I flashed the SSD with a clean install of Ubuntu Server 21 (on my Windows 10 desktop). The SSD has a boot device which is readble from WIndows. I edited cmdline.txt and added

usb-storage.quirks=152d:0578:u

to the end of the single line in that file

dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc quiet splash usb-storage.quirks=152d:0578:u

The 152d:0578 is the ID of my USB controller.

Plug the SSD into the Pi 4 and, voila, it boots and works

 

 

NHIbernate, Sybase and .NET Core

28 June 2021

The Problem

I was working on a system utilising .NET 4.x and Sybase. This combination is not supported by Entity Framework so NHibernate was used.

It was planned to migrate the project to .NET Core, however a number of issues were encountered ustilising NHibernate.

Much investigation was performed, espcially using Resharper to disassemble the Sybase driver

The solution is shown below. Voila, you can use .NET Core and NHibernate and Sybase.

Solution Attempt Number 1

Code

  • Create WebAPI project on DotNet Core 3.1
  • Add references to NHibernate 5.2.7

Errors

Discussion

It appears that the NHibernate code cannot find the the Sybase ASE driver Sybase.ADONet2.AseClient installed as part of the nuget package

 

Solution Attempt Number 2

Code

As per Verrsion 1 but with

  • NHibernate 5.2.7 Source code downloaded and .csproj added to solution and references instead of NHibernate nuget package (so can step through code)
  • Reference added to Sysbase DLLs

Errors

Discussion

An exception is thrown in the Sybase.AdoNet2.ASeClient.dll in the constructor which calls LoadLibraries():

NB Disassembly of the driver done by ReSharper

The error is thrown at the line 252 on the Directory.GetAccessControl method – this is not supported in .Net Core:

https://stackoverflow.com/questions/41584932/support-for-file-security-in-net-core

The “workaround” suggested does not appear to work within the context of the Driver (not known why but driver might run in a restricted execution context). This article also discusses the driver error and that some System.IO methods have been removed in dotnetcore.

The Real Solution

Code

  • Add AdoNetCore.AseClient nuget package – this is a 3rd party Sybase ASE driver
  • Reference NHibernate nuget version 5.2.7
  • Add Driver classes as below

These files  are “driver” classes customised to use the AdoNetCore.AseClient driver. These are “copies” of the equivalent files in the NHibernate source code with the following modifications

The above specification for connection.driver_class is necessary as “full assembly specification” giving assembly name and class name otherwise NHibernate doesn’t know in which DLL to “looK” for the class.

The CustomDialect class was changed to reference these files:

 

Discussion

he  connection.driver_class specification in SybaseASECoreDialect was the only “tricky” thing to “get right”.  In the NHibernate “virgin” SysbaseASE15Dialect only specifies the “Driver” class name for the connection.driver_class

 

The NHibernate can “find” Nhibernate.Driver.SybaseAseClientDriver as it is contained within the NHibernate DLL. Using the custom classes it is necessary to specify the “full name” as the code is in separate assembly