Wprowadzenie

Artykuł jest kontynuacją pierwszego wpisu dotyczącego platformy Docker: .NET Core – wprowadzenie do platformy Docker

W tej części skupimy się na utworzeniu obrazu i uruchomieniu kontenera z naszą aplikacją. Nie będę jednak skupiał się na pierwszym kroku, tj. tworzeniu nowej aplikacji. Jedynym wymaganiem jest utworzenie aplikacji konsolowej w technologii .NET Core, która po uruchomieniu wyświetli:

using System;

namespace sample_app
{
	class Program
	{
		static void Main(string[] args)
		{
			Console.WriteLine("Witaj swiecie prosto z Dockera!");
			Console.ReadKey();
		}
	}
}
Jeżeli Docker jest dla Was nowością zapraszam do pierwszej części artykułu, która płynnie wprowadzi Was w podstawy jego użycia. Jeżeli wszystko macie zainstalowane, aplikacja została utworzona, zapraszam do właściwej części wpisu.

Konteneryzacja aplikacja utworzonej w .NET Core

W pierwszym kroku przechodzimy do folderu w którym utworzyliśmy nasz projekt i otwieramy dowolny edytor tekstowy. Musimy utworzyć plik konfiguracyjny dla naszego projektu. Dodajemy poniższe instukcje (szczegółowe wyjaśnienie poniżej) oraz zapisujemy w głównym katalogu projektu pod nazwą Dockerfile - koniecznie bez rozszerzenia.

FROM microsoft/dotnet:2.0-sdk
WORKDIR /sample-app/

# kopiujemy plik .csproj oraz używamy polecenia dotnet restore
COPY *.csproj ./
RUN dotnet restore

# kopiujemy i dokonujemy build'a całej reszty
COPY . ./sample-app
RUN dotnet build -c Release
ENTRYPOINT ["dotnet", "run", "-c", "Release", "--no-build"]
Instrukcje Docker są wykonywane sekwencyjnie co wykorzystamy w kolejnej części artykułu dotyczącej optymalizacji tworzonych obrazów.

Pierwszym poleceniem w pliku konfiguracyjnym jest zawsze FROM.

FROM microsoft/dotnet:2.0-sdk
Instrukcja te iniciuje nowy build oraz definiuje podstawowy obraz dla pozostałych instrukcji. W zależności od ustawionego trybu kontenera dojdzie do pobrania wersji Windows lub Linux. Ta druga charakteryzuje się dużo mniejszym rozmiarem. W naszym przypadku będziemy korzystać z obrazu microsoft/dotnet:2.0-sdk. Jeżeli obraz ten znajduje się na dysku cały proces będzie zdecydowanie szybszy. W pierwszej cześci artykułu korzystaliśmy z polecenia pull, aby pobrać wymagane obrazy na dysk.

Instrukcja WORKDIR ustawia katalog roboczy dla pozostałych instrukcji zawartych w pliku konfiguracynym, tj. RUN, ENTRYPOINT oraz COPY. Jeżeli ten katalog nie istnieje dojdzie do jego utworzenia. W naszym przypadku folderem robocznym jest sample-app.

WORKDIR /sample-app

Instrukcja COPY kopiuje nowe pliki lub katalogi ze ścieżki źródłowej i dodaje je do docelowego systemu plików kontenera. Za pomocą tej instrukcji kopiujemy plik projektu do kontenera:
COPY *.csproj ./

Instrukcja RUN wykonuje wszystkie polecenia w nowej warstwie nad bieżącym obrazem i zatwierdza zmiany. Na tym etapie przygotowaliśmy nasz obraz i jesteśmy gotowi do kolejnego kroku. Polecenie dotnet restore pozwala na pobranie wszystkich niezbędnych zależności:

RUN dotnet restore

Polecenie COPY kopiuje pozostałe pliki do naszego kontenera na nowo utworzoną warstwę.

COPY . ./

Opublikowanie aplikacji odbywa się za pomocą instrukcji RUN z dodatkowymi parametrami. Polecenie dotnet publish kompiluje aplikację, przechodzi przez plik z zależnościami i publikuje wynik tej operacji do domyślnego folderu wynikowego. Za pomocą opcji -c (configuration) konfigurujemy tryp projektu na Release.

RUN dotnet publish -c Release

Ostatnim poleceniem w tym wypadku jest ENTRYPOINT - pozwala na uruchomienie kontenera jako pliku wykonywalnego oraz definiuje jak powinien zachowywać się obraz po uruchomieniu:

ENTRYPOINT ["dotnet", "run", "-c", "Release", "--no-build"]
Dodatkowe parametry konfiguracyjne są niezwykle istotne. Ponownie używamy opcji konfiguracyjnej Release - w przeciwnym wypadku dojdzie do próby uruchomienia w trybie Debug co wiąże się z ponowym budowaniem aplikacji (jest to niepotrzebne ponieważ build) został już zrobiony. Flaga --no-build używana jest tylko do upewnienia się, że użyjemy kompilacji utworzonej w poprzednim kroku. Jeżeli, z jakiegoś powodu, nie uda się znaleźć tej wersji zastosowana flaga zwróci błąd ponieważ nie będzie w stanie samodzielnie wykonać kompilacji.

Nasz plik Dockerfile pozwala na:

  • utworzenie obrazu z naszą aplikacją;
  • przekopiowanie niezbędnych zależności do nowo utworzonego obrazu;
  • build aplikacji, która działa jako plik wykonywalny.

Budowanie i uruchamianie aplikacji

Plik Dockerfile jest gotowy, poszczególne elementy zostały wyjaśnione. Z poprzedniego artykułu pamiętacie, że konterem nazywamy działający obraz. Wykonajmy teraz kolejny krok – zbudujemy kontener:

docker build -t sample-app .
Może to być dość długi proces ale każdy krok pośredni będzie doskonale udokumentowany – będziecie na bieżąco z postępem: Docker: przykładowa aplikacja Sam obraz również został utworzony: Docker: lista obrazów

Możemy teraz przejść do ostatniego kroku (na tym etapie) jakim jest uruchomienie naszego kontenera. Użyjemy do tego poniższego polecenia:

docker run sample-app
Jeżeli wszystko przebiegło pomyślnie na konsoli powinniście zobaczyć: Docker: uruchomienie aplikacji

Podsumowanie

Co udało nam się osiągnąć:

  • utworzyliśmy aplikację konsolową w technologii .NET Core;
  • utworzyliśmy plik Dockerfile, który pozwolił nam na utworzenie pierwszego obrazu oraz kontenera;
  • zbudowaliśmy i uruchomiliśmy pierwszą aplikację (dokonaliśmy konteneryzacji).

Jedyne co może nas zastanawiać to wielkość utworzonego obrazu. 1.79GB to zdecydowanie za dużo jak na zwykłą aplikację konsolową. Dlatego w kolejnym artykule przedstawię pojęcie wielopoziomowego budowania.