Docker para desarrollo en C# / Sudo Null IT News

Hace aproximadamente un par de años descubrí una gran herramienta en el arsenal del desarrollador llamada Estibador. En pocas palabras, Docker es una plataforma abierta para desarrollar, entregar y operar aplicaciones. El propio Docker funciona según el principio de virtualización, es decir, cada aplicación es una imagen virtual que se coloca en un contenedor. Docker aprovecha la capacidad del sistema operativo para crear contenedores aislados. Un contenedor se diferencia de una máquina virtual en que el contenedor no emula hardware y utiliza el sistema operativo host.

Con Docker, la aplicación estará aislada de forma segura en un contenedor. Es posible administrar y limitar características del contenedor como CPU, Memoria y otras, así como monitorear el rendimiento y el consumo de recursos.

Las capacidades de Docker son bastante amplias, pero en este artículo me gustaría centrarme en tres:

  • La capacidad de implementar aplicaciones de infraestructura de forma rápida y segura (Postgres, Rabbit, Redis y otras),

  • La capacidad de monitorear el funcionamiento y uso de los recursos de su propia aplicación en un entorno aislado,

  • Posibilidad de publicar varias aplicaciones interactuando entre sí en una red privada virtual, como por ejemplo: microservicios,

Infraestructura en Docker.

Docker le permite desarrollar y depurar aplicaciones de forma segura y rápida en su máquina local y experimentar con diferentes componentes o incluso conjuntos de componentes de infraestructura.

Al utilizar Docker, no es necesario instalar y configurar una base de datos, caché o intercambiador localmente. Deje que estos componentes residan en imágenes de Docker. Además, lo más probable es que ya existan imágenes de dichos componentes en Docker Hub.

Entonces, por ejemplo, para implementar Postgres necesitas ejecutar:

docker run --name habr-pg-13.3 
-p 5432:5432 
-e POSTGRES_USER=habrpguser 
-e POSTGRES_PASSWORD=pgpwd4habr 
-e POSTGRES_DB=habrdb 
-d postgres:13.3

Cuando ejecute el comando, la imagen se descargará. postgres: 13.3 y comenzará en el puerto 5432 con usuario habrpgusercontraseña pgpwd4habr y el nombre de la base de datos habrdb.

¡Eso es todo! ¡Postgres está funcionando! Ahora se puede utilizar para el desarrollo de aplicaciones. Quizás el único lugar no trivial en el lanzamiento sean los puertos. Es importante entender aquí que los contenedores viven en su propio ecosistema, y ​​por eso cada contenedor tiene dos tipos de puertos: internos - para su ecosistema y externos - para el acceso desde el exterior.

¡Eso es todo! ¡Postgres está funcionando! Ahora se puede utilizar para el desarrollo de aplicaciones. Quizás el único lugar no trivial en el lanzamiento sean los puertos. Es importante entender aquí que los contenedores viven en su propio ecosistema, y ​​por eso cada contenedor tiene dos tipos de puertos: internos – para su ecosistema y externos – para el acceso desde el exterior.

¡Eso es todo! ¡Postgres está funcionando! Ahora se puede utilizar para el desarrollo de aplicaciones. Quizás el único lugar no trivial en el lanzamiento sean los puertos. Es importante entender aquí que los contenedores viven en su propio ecosistema, y ​​por eso cada contenedor tiene dos tipos de puertos: internos - para su ecosistema y externos - para el acceso desde el exterior.

Después del lanzamiento, aparecerá un contenedor con el nombre en Docker Desktop. habr-pg-13.3:

Aplicación en envase.

Si todo está claro con la infraestructura y solo necesitas encontrar la imagen deseada, descargarla y ejecutarla en un contenedor, entonces con tu propia aplicación no todo es tan sencillo. Para crear una imagen de Docker, debe crear un Dockerfile.

Si usa Visual Studio, el propio editor proporciona esta opción si agrega “Soporte Docker”:

Si seleccionamos, por ejemplo, la plataforma Linux, obtenemos el siguiente Dockerfile:

FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ("Dir/App.csproj", "Dir/")
RUN dotnet restore "Dir/App.csproj"
COPY . .
WORKDIR "/src/Dir"
RUN dotnet build "App.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "App.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ("dotnet", "App.dll")

Las imágenes se descargan aquí. mcr.microsoft.com/dotnet/runtime:6.0 y mcr.microsoft.com/dotnet/sdk:6.0luego el directorio con el proyecto se coloca en el contenedor, se restauran todas las dependencias utilizadas por el proyecto, luego el proyecto se construye en modo de lanzamiento, se ejecuta la publicación, se hacen copias y el comando se declara como punto de entrada dotnet app.dll aplicaciones. Además, el perfil de inicio “Docker” aparecerá en VS Studio.

Después del lanzamiento, se creará un contenedor con nuestra aplicación en Docker Desktop. Si lo seleccionamos en la lista, podemos ver los registros; además de los registros, podemos ver las pestañas Inspeccionar, donde se muestran los parámetros de lanzamiento, y Estadísticas, donde se muestran las estadísticas de los recursos utilizados por el contenedor.

Además de las pestañas, hay botones de control de contenedor, Detener, Reiniciar, Eliminar, Abrir en el navegador, CLI. De particular interés aquí es el comando Cli, que abrirá una terminal en el contenedor. Otra forma de abrir la terminal: escribir en la línea de comando

docker exec -it <имя контейнера> /bin/bash

Varios editores como VS y VS Code tienen extensiones para ver y trabajar con el contenido de los contenedores. Específicamente en VS Code:

Microservicios. Docker componer.

Ejecutar una aplicación en un contenedor fue bastante fácil, especialmente usando VS, pero ¿cómo se implementan múltiples aplicaciones relacionadas? Por supuesto, puede iniciar un grupo de aplicaciones por separado cada vez y los componentes de la infraestructura por separado. Sí, esta opción, por lo general, nos proporcionará un grupo de servicios, pero gestionar su configuración será bastante problemático. ¿Cómo puede ser esto? Para este caso, existe Docker Compose. Docker Compose se utiliza para gestionar simultáneamente varios contenedores que componen una aplicación.

Para utilizar Docker Compose, debe generar un archivo docker-compose.yml. Este archivo configura todos los contenedores que armamos:

version: '3.8'

networks:
    app-net:
        external: false

services:
    app1:
        image: app1:latest
        container_name: app1
        hostname: app1
        depends_on:
            - mongo_image
            - rabbitmq_image
        build:
            context: "../"
            dockerfile: "App1/Dockerfile"
        ports:
            - "63696:63696"
            - "63695:63695"
        environment:
            - ConnectionStrings__mongo=mongodb://mongo_image:27017/app?appName=app&waitQueueMultiple=7&maxPoolSize=100
            - ConnectionStrings__Queues=amqp://myuser:mypass@rabbitmq_image:5672/app
            - ASPNETCORE_ENVIRONMENT=Production
            - ASPNETCORE_URLS=
            - ConnectionStrings__redis=redis:6379
        networks:
            - app-net
    app2:
        image: app2:latest
        container_name: app2
        hostname: app2
        environment:
            - ASPNETCORE_URLS=
            - ConnectionStrings__redis=redis:6379
            - Cors=("
            - ConnectionStrings__main=Server=postgres_image;User Id=postgres;Password=123;Database=app;Port=5432
        depends_on:
            - postgres_image
            - cache
        build:
            context: "../"
            dockerfile: "App2/Dockerfile"
        ports:
            - "65000:65000"
        networks:
            - app-net
    rabbitmq_image:
        image: rabbitmq:3.8.8-management
        ports:
            - 5673:5672
            - 15673:15672
        restart: always
        networks:
            - app-net
        environment:
            RABBITMQ_DEFAULT_VHOST: app
            RABBITMQ_DEFAULT_USER: myuser
            RABBITMQ_DEFAULT_PASS: mypass
    mongo_image:
        image: mongo:4.2.8
        ports:
            - "27019:27017"
        restart: always
        environment:
            MONGO_INITDB_DATABASE: app
        networks:
            - app-net
    postgres_image:
        image: postgres:11
        ports:
            - "5431:5432"
        restart: always
        environment:
            POSTGRES_USER: "postgres"
            POSTGRES_PASSWORD: "123"
            POSTGRES_DB: "app"
        networks:
            - app-net
    cache:
        image: redis:latest
        hostname: redis
        restart: always
        ports:
            - '6379:6379'
        command: redis-server --save 20 1 --loglevel warning
        networks:
            - app-net
    app3:
        image: app3:latest
        container_name: app3
        hostname: app3
        depends_on:
            - rabbitmq_image
            - clickhouse_image
            - cache
            - app1
        build:
            context: "../"
            dockerfile: "App3/Dockerfile"
        environment:
            - ConnectionStrings__Queues=amqp://myuser:mypass@rabbitmq_image:5672/app
            - ConnectionStrings__ClickHouse=Host=clickhouse_image;Port=9000;Database=default
            - app__url=
            - DOTNET_ENVIRONMENT=Production
        networks:
            - app-net

Aquí se describen tres servicios: app1, app2, app3 y componentes de infraestructura: Rabbitmq_image, mongo_image, postgres_image, caché, a través de variables en la sección de entorno, se pasan parámetros para vincular servicios entre sí, así como la infraestructura. Los parámetros de la sección de entorno se mostrarán en la pestaña Inspeccionar de cada contenedor. Todos los componentes están ubicados en la red de aplicaciones. Para implementar todos estos componentes, debe llamar los comandos desde el directorio con el archivo:

  • compilación de composición acoplable

  • Docker-componer

Un archivo de este tipo se puede crear a mano, pero en VS es posible automatizar este proceso agregando un orquestador de contenedores:

Después de agregar soporte para el orquestador de contenedores, se agregará soporte para docker-compose, en el cual, de acuerdo con el ejemplo mostrado anteriormente, puede configurar un soporte a partir de los componentes necesarios.

Es fácil notar que han aparecido los archivos .dockerignore, docker-compose.yml y docker-compose.override.yml, donde los dos últimos definen el docker-compose final. Vale la pena señalar que puede haber muchos más archivos .yml, por ejemplo: para separar temáticamente servicios entre sí.

Es fácil notar que han aparecido los archivos .dockerignore, docker-compose.yml y docker-compose.override.yml, donde los dos últimos definen el docker-compose final. Vale la pena señalar que puede haber muchos más archivos .yml, por ejemplo: para separar temáticamente servicios entre sí.

Para que las aplicaciones funcionen correctamente, es importante especificar correctamente las cadenas de acceso a los componentes y servicios de la infraestructura. Separar los contenedores en una red separada garantiza su aislamiento de las aplicaciones externas y les permite interactuar entre sí. Al proporcionar los parámetros de inicio correctos en la sección de entorno y los parámetros de infraestructura, obtenemos una base lista para usar de varias aplicaciones que puede implementar cualquier persona que tenga Docker y acceso a Internet.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *