Docker i Ngrok
Jeżeli znasz już Dockera na poziomie przynajmniej podstawowym – czyli potrafisz uruchamiać kontenery oraz wiesz jak z nich korzystać na swoim komputerze – ten post jest dla Ciebie.
Pokażę Ci jak za pomocą Dockera oraz narzędzia Ngrok – opublikować aplikację w internecie.
Wyzwanie
Naniosłeś jakieś zmiany w aplikacji (np. w UI) i chciałbyś je na szybko zaprezentować koledze z zespołu. Na przykład, żeby ocenił czy to, co robisz, ma sens. Standardowy proces to quick call i udostępnianie ekranu na komunikatorze, który używacie w firmie.
Jeżeli jednak kolega z zespołu, chciałby to samodzielnie przeklikać albo podglądnąć jak zachowuje się aplikacja u siebie – raczej nie pozostaje nic innego jak zrobienie commita i wdrożenie naniesionych zmian na jakieś środowisko testowe.
Tutaj już zależy, jak sprawny jest wasz proces CI/CD i jak szybko jesteście w stanie wdrożyć zmiany.
Jeszcze lepszy przykład
Środowisko testowe nie jest udostępnione do internetu (działa tylko w sieci firmowej).
Twoja aplikacja (webowa) ma działać “dobrze”, niezależnie od rozdzielczości ekranu. Chciałbyś więc podglądnąć zmiany z Twojego smartfona (bo przecież masz go cały czas przy sobie).
BOOM.
Znowu trzeba kombinować. Konfigurować VPN-y albo inne cuda.
Ngrok – co to jest?
W bardzo dużym skrócie – ngrok jest narzędziem (i usługą), które umożliwia przekierowanie ruchu z publicznego adresu IP (domena ngrok.io) do usługi uruchomionej na Twoim komputerze.
Nie będę się tutaj rozwodził, jak to dokładnie działa “pod spodem”, ponieważ zostało to dość obszernie opisane w dokumentacji.
Posłużymy się tą usługą/narzędziem do opublikowania aplikacji uruchomionej z poziomu Dockera. Co ciekawe, nie będziemy nic instalować. Na Docker Hubie znajduje się obraz, który wystarczy użyć.
I LOVE IT.
Za to właśnie uwielbiam Dockera. Chcesz skorzystać z jakiegoś fajnego narzędzia/rozwiązania i najczęściej jest do tego gotowy obraz. Bierzesz, uruchamiasz – działa!
Docker i Ngrok – pierwsze kroki
Na początku potrzebujemy stworzyć sieć dockerową. Będzie to sieć typu bridge. Więcej informacji na ten temat możesz znaleźć w jednej z lekcji DEMO mojego kursu online Docker Maestro.
docker network create -d bridge ngrok-network
Uruchom kontener o nazwie mynginx, na podstawie oficjalnego obrazu nginxa.
WAŻNE: podłącz go do nowo utworzonej sieci ngrok-network. Jeżeli jesteś ciekawy, dlaczego jest to kluczowe – zaglądnij tutaj.
docker container run -d -p 8080:80 --network ngrok-network --name mynginx nginx:1.17.1
Kontener będzie dostępny na http://localhost:8080/

Uruchom kontener o nazwie ngrok, bazując na obrazie wernight/ngrok
. Musi on być podłączony do wcześniej utworzonej sieci ngrok-network, do której w poprzednim kroku podłączony został kontener mynginx.
Dzięki temu, ngrok będzie mógł komunikować się z kontenerem mynginx za pomocą DNS – (na przykład http://mynginx).
Otwórz ruch z portu 4040 – dzięki czemu będziesz mieć dostęp do UI ngroka. Na koniec przekaż nazwę kontenera mynginx oraz port, na którym działa.
UWAGA: przekazujemy tutaj port 80. Wynika to z tego, że jest to domyślny port, na którym działa nginx w kontenerze.
docker container run -d -p 4040:4040 --network ngrok-network \ --name ngrok wernight/ngrok ngrok http mynginx:80
Możesz teraz przejść do przeglądarki i użyć adresu http://localhost:4040.
Twoim oczom ukaże się interfejs, gdzie podglądniesz twój publiczny adres URL stworzony przez ngroka.

W moim przypadku jest to http://352dd73fe4bf.ngrok.io/
U Ciebie będzie to inny adres, ponieważ ngrok generuje adresy dynamicznie.
Teraz każdy, kto ma powyższy adres URL, może podglądnąć naszego nginxa.

Lokalny development aplikacji
OK – wiemy już, jak to wszystko działa. Czas na przykład z życia wzięty, czyli lokalny development aplikacji.
Posłużę się tutaj przykładową aplikacją NodeJS, ale może to być aplikacji w dowolnej technologii.
Aplikacja ma dwa zwracające dane endpointy.
Pierwszy to /services/projects
zwracający listę projektów, a drugi zwracający ich szczegóły /services/projects/:id
const express = require( 'express' ) const appRouter = express.Router() const projects = require( './data' ) appRouter.get( '/services/projects', function( req, res ) { res.json({ code: 'success', payload: projects }) }) appRouter.get( '/services/projects/:id', function( req, res ) { const project = projects.find( p => p.projectId === parseInt( req.params.id ) ) res.json({ code: 'success', payload: project }) }) module.exports = appRouter
Dla tej aplikacji przygotowałem następujący Dockerfile
FROM node:14.4.0-buster-slim ARG NODE_ENV=production ENV NODE_ENV $NODE_ENV WORKDIR /app ARG PORT=8080 ENV PORT $PORT COPY package.json package-lock.json ./ RUN npm ci COPY . /app USER node CMD [ "node", "src/server.js" ]
Teraz całość zwieńczymy plikiem docker-compose.yml z pomocą, którego zbudujemy obraz oraz uruchomimy całość (już z wykorzystaniem Ngroka)
Plik docker-compose.yml prezentuje się następująco
version: "3.7" services: backend: image: nodejs-app build: context: ./backend args: NODE_ENV: production PORT: "8080" ports: - "8080:8080" ngrok: image: wernight/ngrok ports: - "4040:4040" command: ["ngrok", "http", "backend:8080"]
Teraz nie pozostaje nic innego jak wykonanie polecenia docker-compose build
(aby zbudować obraz), a następnie docker-compose up
Dzięki temu na http://localhost:4040/inspect/http będziemy mieć dostępny UI ngroka – w tym publiczny adres URL, pod którym możemy odpytać API.
Nasza przykładowa aplikacja lokalnie działać będzie na http://localhost:8080/services/projects
Po odczytaniu publicznego adresu URL (w moim przypadku http://4f09a1a0acea.ngrok.io/) wygląda to następująco

Każde przychodzące żądanie jest zapisywane w panelu ngroka.

Spróbuj samodzielnie
Omawianą aplikację, wraz z instrukcją jak to uruchomić znajdziesz na moim GitHubie https://github.com/dnaprawa/nodejs-docker-ngrok
Wystarczy sklonować repozytorium i uruchomić
docker-compose build docker-compose up -d
Życzę miłej zabawy 🙂
PS. Jeżeli artykuł był dla Ciebie przydatny, będę wdzięczny za podzielenie się nim z przynajmniej jedną osobą! Dziękuję!
Świetne!
Dzięki Damian 🙂
Fajnie słyszeć! Dzięki za komentarz Krzysiu 🙂