Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Problemy Docker for Windows

Problemy docker for Windows i jak je rozwiązać

Docker to jedno z narzędzi, które w ostatnim czasie najszybciej zyskuje popularność. Dziś jest on podstawą dużej części rozwiązań po stronie programistów, jak i administratorów. W Internecie można znaleźć wiele artykułów oraz tutoriali pokazujących jak korzystać z dockera i jego możliwości, jednak mało mówi się o problemach wynikających z połączenia Docker + Windows.

Najczęstsze problemy

Jeżeli jesteś jedną z osób które mimo, że podążają krok w krok za najprostszym przykładem nie są w stanie wykonać danego zadania to ten artykuł jest dla ciebie. Docker for Windows boryka się z wieloma bolączkami, których rozwiązanie jest często poza zasięgiem normalnego śmiertelnika. Przykładami mogą być:

  • docker volumes nie działa bez podania żadnego błędu,

  • network i volumes nie działa w docker-compose,

  • mój VPN sprawia, że kontenery przestają działać,

  • docker-compose czasami chce listę jako argument, czasami string,

  • Docker zacina się, kiedy w custom context próbujesz przekopiować za duży folder

Najczęściej można spotkać się ze stwierdzeniem, że zmiana na Hyper-V naprawia większość tych problemów. Jednak z własnego doświadczenia wiem, że wersja ta wprowadza nowe ograniczenia i w większości nic nie zmienia. Mimo że te błędy występują od wielu wersji i są dobrze udokumentowane, to żadne z podanych tam innych rozwiązań (np. downgrade dockera) nie pomoże ze wszystkimi.

Żeby było jasne należy pamiętać o tym, że docker jest przełomowym narzędziem w dzisiejszym rynku IT oraz dalej prężnie rozwijanym projektem open source. Liczę, że kiedyś uda się rozwiązać wszystkie problemy, które występują w wersji na Windowsa, ale trzeba sobie radzić już dziś.

Jak było - Korzystanie z VM

Wcześniej jedynym rozwiązaniem było korzystanie z maszyny wirtualnej z postawionym tam systemem linuxowym. Zdecydowanie utrudniało to jakąkolwiek pracę nie tylko z dockerem, ale z samym programowaniem. Zabierało to również sporą część zasobów komputera, tak potrzebnych w pracy developera. Przy dużych projektach korzysta się z połączenia vagranta i dockera, aby uzyskać spójne środowisko. Natomiast w projektach jednoosobowych i w mniejszych zespołach znacznie łatwiej używać dockera z wsl2.

Jak jest - Korzystanie z WSL2

O samym Windows Subsystem for Linux 2 można przeczytać tutaj. Uogólniając, wsl2 pozwala użytkownikom Windowsa na uruchomienie środowiska Linuxowego bez użycia wirtualnej maszyny. Druga wersja tego narzędzia wprowadziła wiele udogodnień i aktualności w tym pełną integracje z kontenerami dockerowymi. Możliwości jakie daje to narzędzie można już zobaczyć przy najprostszym przykładzie aplikacji napisanej w JavaScript i Node.js

Przygotowanie środowiska pod WSL2

Aby wyzbyć się większości problemów należy otworzyć projekt przy pomocy WSL2. Żeby to zrobić potrzebne będzie:

  1. Zainstalowane WSL2 oraz dowolna dystrybucja linuxa (np. Ubuntu), którą można ściągnąć z Microsoft Store.

  2. Ściągnąć i zainstalować Dockera z strony projektu. Wraz z najnowszą aktualizacją można to też zrobić na wersji Home systemu Windows. O samej kompatybilność wstecznej można przeczytać tutaj.

  3. W Docker Desktop w zakładce resources należy włączyć wsl integration i wybrać zainstalowaną wersje linuxa.

  4. Do Visual Studio Code zainstalować dodatek Remote - WSL. Umożliwia on połączenie się z poziomu edytora do subsystemu linuxowego.

Jeden prosty trick - zobacz jak

Przejdźmy teraz do samego programu. Będzie to prosta aplikacja node.js, która zostanie otwarta przy pomocy dockera i wsl2.

W nowo stworzonym folderze przy pomocy komendy npm init --y zostaje zainicjonowany projekt i następuje instalacja bibliotek Express.js oraz Nodemon:

npm init -y
npm i express
npm i -g nodemon

Następnie tworze plik app.js. Struktura projektu wygląda następująco:

image-20200826104206092

Jest to prosta aplikacja, która pokazuje wpisany tekst. Celem tutaj nie jest sam program ale pokazanie działania Dockera oraz wsl2. Sam program prezentuje się tak:

const express = require("express");
const app = express();

app.get("/", (req, res) => res.send("Witam ;)"));
app.listen(8080, () => console.log("Server is up!"));

Żeby stworzyć kontener należy utworzyć plik Dockerfile, w którym zawarte są instrukcję, które mają się wykonać w czasie budowania obrazu oraz .dockerignore, gdzie znajdują się ignorowane pliki.

#Dockerfile
FROM node:latest as build-env
ADD . /app
WORKDIR /app
RUN npm install

FROM mhart/alpine-node:latest
COPY --from=build-env /app /app
RUN npm install -g nodemon
WORKDIR /app
EXPOSE 8080
CMD ["nodemon", "app.js"]
#.dockerignore
.git
node_modules
Dockerfile
.dockerignore

W pierwszej linijce określony zostaje obraz, na podstawie którego zostaje zbudowany projekt. Następnie dodawany jest folder /app, gdzie będzie znajduje się aplikacja. Zaraz potem bieżący katalog ustawiany jest jako katalog roboczy. Komenda RUN npm install instaluje w kontenerze biblioteki potrzebne do uruchomienia programu.

Wszystkie te kroki zawarte są w części budowy nazwanej build-env. Żeby oszczędzić miejsce na dysku, używa się multi-stage builds, które pozwala na podział fazy budowania na poszczególne etapy.

Druga część Dockerfile opiera się na obrazie apline. Obrazy te są tworzone w taki sposób, żeby miały jak najmniejszy rozmiar. Następnie kopiowana jest część build-env. Znowu ustawiany jest katalog roboczy i określone zostaje, na jakim porcie działa aplikacja (8080).

Aktualna struktura projektu:

image-20200826152603842

Normalnie, wraz z każdą zmianą w kodzie konieczne byłoby przebudowywanie kontenera do nowszej wersji. Staje się to bardzo kłopotliwe przy większych projektach lub kiedy korzysta się z wielu połączonych ze sobą kontenerów poprzez docker-compose, gdzie czas potrzebny na tę operację może sięgać nawet parunastu minut. Aby tego unikać od strony frontendu korzysta się z Nodemona, który automatycznie restartuje serwer z nowymi zmianami. Jednak kiedy wprowadzimy zmiany u siebie na komputerze to zmiany nie zostaną odzwierciedlone w kontenerze.

Korzystanie z WSL2 + Docker

Aby mieć stuprocentową pewność, że Docker będzie działał poprawnie należy przełączyć się na WSL2. Żeby to zrobić:

  1. Kliknąć F1, wpisać Remote - WSL reopen folder in distro
  2. Otworzyć folder w wybranej wersji linuxa

Okno zostanie przeładowane i projekt zostanie otwarty w wsl2.

image-20200826165018205

Żeby zbudować obraz należy użyć komendy:

docker build -t demo .

W podanym przykładzie demo to tag obrazu, a kropka oznacza bieżący katalog. W terminalu widać poszczególne kroki, które zostały zadeklarowane w pliku dockerfile.

Aby uruchomić aplikacje należy użyć komendy:

docker run -p 8080:8080 -v /mnt/c/Users/folder_na_dysku_c:/app demo

Gdzie:

  • flaga -p wskazuje jaki port na komputerze ma odpowiadać portowi z kontenera.

  • flaga -v definiuje połączenie pomiędzy folderami na komputerze, oraz folderami z kontenera.

    /mnt/c/Users/folder_na_dysku_c to ścieżka katalogu na moim komputerze natomiast /app to katalog znajdujący się w kontenerze.

    image-20200827090332058

Sama aplikacja prezentuje się następująco:

image-20200827090439577

Teraz każda zmiana wykonana w kodzie spowoduje przeładowanie się projektu i zmiany zostaną od razu odwzorowane na serwerze jak i w kontenerze.

image-20200827090631000

Podsumowanie

Przedstawione powyżej rozwiązanie pokazuje sposób, w jaki można uniknąć wielu problemów związanych z używaniem Dockera i które osobiście preferuję niezależnie od tego, jaki projekt realizuję. Mam nadzieję, że opisany przykład pomoże, chociaż odrobinę w zrozumieniu działania Dockera + wsl2 i używania ich w sposób bezproblemowy.

@KrzysztofZawisla

This comment has been minimized.

Copy link

@KrzysztofZawisla KrzysztofZawisla commented Aug 27, 2020

Dockerek <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment