Skip to content

Commit

Permalink
fix PostgreSqlConnectorScripts.RemoveAllScript in Azure
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed Feb 13, 2020
1 parent df215a2 commit f9cc544
Showing 1 changed file with 1 addition and 0 deletions.
1 change: 1 addition & 0 deletions Signum.Engine/Connection/PostgreSqlConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_class pc, pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relname NOT LIKE 'pg_%'
AND pc.relkind IN ('v', 'm')
) LOOP
EXECUTE format('DROP VIEW %I.%I;',
Expand Down

10 comments on commit f9cc544

@olmobrutall
Copy link
Collaborator Author

@olmobrutall olmobrutall commented on f9cc544 Feb 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Southwind inside of a Docker Container and running in Azure

I've spent the last days dockerizing Southwind. This is the related commit.

There were a few issues upgrading Signum.TSGeneator and Signum.MSBuildTask to .Net Core 3.1 and fixing casing in some TS files, but except for that everything worked nicely.

Why Docker?

Docker has been around since 2013 and it's currently a very popular technology. It combines the lightweight of a Process with the OS isolation of a Virtual Machine.

This is huge for many solutions, but not so important for the typical Signum Framework application:

  • It simplifies deploying applications with many different dependencies that need to be installed --> Signum Framewok applications only typically require the latest .Net Core Hosting Bundle.
  • It simplifies deploying many services in a Microservice Achitecture --> Signum Framework applications are a Majestic Monolith
  • By making deployments standard, you can use Kubernetes or Docker Swarm to scale your back-end --> Scaling the back-end is the easy part, in a LOB application the performance is typically the database. Most of the times adding the right database index or rewriting a query will have a much bigger impact.

Still, being able to do this kind of stuff in a Signum Framework application can be useful in some cases.

There are other more down-to-earth advantages for using Docker:

  • There are many CI/CD alternatives (GitHub Pipeline, Gitlab pipelines, Teamcity, Azure DevOps) all with his own XML / YAML configuration. By putting more of the build script in a Dockerfile you can standarize no only the deployables but also the build process.
  • An B1 Web App for Containers cost 11€/month, while a normal Windows B1 Web App costs 27€/Month. Compare Azure prices here.

Installing Docker for Windows

Install Docker for Windows.

Debugging Southwind.React with with Visual Studio

In Visual Studio, F5 (Play) button, choose Docker and play. Visual Studio will look for a Dockerfile in the Southwind.React folder and only read the first lines to check the base image, then create a custom (aka Magic) docker container with shared folders, so changes in the website are automatically reflected inside of the docker. It makes a great development experience but not a great way of learn how docker works. More info here.

Creating a Docker image with the CLI

Got to Southwind folder (the one with Southwind.sln file) and run docker build.

docker build -f ".\Southwind.React\Dockerfile" . -t southwind

This will create a Docker image tagged as southwind. An image is like a CD or a Zip file containing your application and all the dependencies. Images are stacked on top of each other after any change in the dockerfile, and identical images can be cached and identified by his SHA. Very much like how Git commits stack on top of each parent.

A tag is a non-unique name for an image.

You can then run the image doing:

docker run -d -p 8080:80 --name southwind_container southwind

This will create a docker container named southwind_container from the southwind image and start it. A container is a running image.

You can list, start, stop, or remove containers with the CLI, or use Visual Studio Containers window for it.

It's not a good idea to have the connection strings inside of the docker image. Instead you can pass it as an environment variable:

docker run -d -p 8090:80 --env ConnectionStrings__ConnectionString='Server=tcp:YOURSERVER.database.windows.net,1433;Initial Catalog=YOURDATABASE;Persist Security Info=False;User ID=YOURLOGIN;Password=YOURPASSWORD;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;' --name southwind_server southwind

Pushing to Azure

Finally in your Azure Portal you have to create a Container Registry (they cost money, choose the cheap one or reuse another one). I named mine southwindcr.azurecr.io. You will get a username and password.

You can use VisualStudio to publish, or use the docker cli:

docker login southwindcr.azurecr.io
## Write your username and password

docker tag southwind southwindcr.azurecr.io/sample/ver1
## tags southwind image with a new server-relative tag, otherwise you can not push

docker push southwindcr.azurecr.io/sample/ver1

Finally in Azure create the Web App for Containers:

  • In Basics tab choose your ResourceGroup, Name, publish (Docker Container), Operative System (Linux), Region (Western Europe) and Sku and size (B1). Then in the Docker tab.
  • In Docker tab choose Image Source (Azure Container Registry), registry (sourwindcr) and image (sample/ver1).

Once the App Service is created go to Settings > Configuration and add an environment variable for ConnectionStrings__ConnectionString with your secret connection string.

I've created two App Settings, one with an Sql Server connection string (https://southwindsqlserver.azurewebsites.net/) and one for PostgreSQL (https://southwindpostgres.azurewebsites.net/)

Azure SQL Server vs PostgreSQL

Both SQL Server and PostgreSQL are configured to spend about 25€/Month (under my 150€/Month Credit of my Enterprise MSDN subscription). But I think Azure SQL Server is substantially slightly faster for the same price in Azure.

Dockerize Southwind.Terminal?

It's definitely possible to dockerize Southwind.Terminal (aka Southwind.Load) too, but since deploying to Staging requires creating migrations interactively and the Docker file-system is read-only I'm not sure if it's worth that the first time you test running the Terminal in a Linux environment is when deploying to Live. Uppercase / lowercase of CSV file paths in CSharp migrations could crash for example.

Happy know your opinion about it.

Enjoy!

@MehdyKarimpour
Copy link
Contributor

@MehdyKarimpour MehdyKarimpour commented on f9cc544 Feb 14, 2020 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ghockx1p
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're on a roll Olmo!

@avifatal
Copy link
Contributor

@avifatal avifatal commented on f9cc544 Feb 14, 2020 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avifatal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remember that it is bad practice to expose .net core to the world.
You have to put a real web-server in front of it.
For example, you can take Nginx / Apache and place it as a reverse proxy. (https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-3.1).
Kestrel is not intended to be exposed to the world. it is just an internal entry point.

@olmobrutall
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine that a Azure Web App is behind some kind of web server. Https was automatic for example.

@olmobrutall
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No... is not:

HTTP/1.1 200 OK
Content-Length: 7263
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-App-Version: 1.0.0.0
Date: Fri, 14 Feb 2020 13:37:56 GMT

@avifatal
Copy link
Contributor

@avifatal avifatal commented on f9cc544 Feb 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the SSL are automatically provisioned by the cloud providers via LetEncrypt. but this can be done for kestrel as well.
When you put Nginx in front, you expose a port for Nginx and let it communicated with .net inside docker network communication.

@olmobrutall
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you expand the dockerfile to have nginx in the middle ?

@avifatal
Copy link
Contributor

@avifatal avifatal commented on f9cc544 Feb 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you add Nginx reverse proxy you add it as an independent container. moreover, this should not be part of your development env.
this should be added to your Kubernetes YAML or docker-compose yaml for deployment.
Also, in general, this is not something you are sharing as part of an opensource project, it is very different between environments, this is not "one suit fits all".
Also, in most cases, you don't add it as a dockerfile, it is more of a service inside docker-compose and you control its settings in docker-compose.yaml,

This is how a typical Nginx reverse proxy looks like, note the proxy_pass line, this is how you point to kestrel internally. app1 is .net core service/container name...

server {
    listen 80;

    server_name myapp.com wwwmyapp.com;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    location / {
        proxy_pass http://app1:5000/;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Please sign in to comment.