Miało być więcej o Angularze, ale ostatnie wygaśnięcie mojego rocznego darmowego planu na Azure oraz całkiem fajny pakiet webowy z kredytami na digitalocean (DigitalOcean: Cloud Computing, Simplicity at Scale) , który był na Humble Bundle… zmotywował mnie, aby trochę zabawić się w DEV OPS.
O instalacji dockerów na ubuntu wspominałem już wcześniej, ale przypomnę trochę tu o nim z miłym dodatkiem w postaci docker-compose. Do tego, co nieco o zabezpieczeniu za pomocą certyfikatu. Kod dostępny jak zawsze na github. Co ważniejsze, zmotywowało mnie to do pracy nad własnymi umiejętnościami oraz pogodzenie się z Ubuntu (Gdyż na Windows Home dockery nie działają, a SSH jest ubogie).

Dev Ops for DUmmies

Docker

Jeśli chodzi o szybkie wdrożenie z budowaniem na zewnątrz, a potem szybką aktualizację na maszynie produkcyjnej, docker zrobił się trochę bez konkurencyjny (nie mówię tu o app services na Azure). Wystarczy, że mamy zainstalowany docker ce lub docker ee (obecnie także k8s) na naszym serwerze i najpierw konfigurujemy na jakich portach ma być nasz obraz otwarty a potem prosty update. Ale zanim dojdziemy do tego, podpowiem, jak skonfigurować projekt z poprzedniego posta pod obraz w dockerze. Plik Dockerfile w naszej solucji służy do tworzenia obrazu dla naszego projektu.

## Obraz potrzebny do budowania aplikacji .NET
FROM Microsoft/dotnet:2.1-sdk AS build
WORKDIR /app
## Instalacja Node  potrzebna do zbudowania  Angulara_React_VUe
RUN buildDeps='gnupg' \
&& set -x \
&& apt-get update && apt-get install -y $buildDeps --no-install-recommends \
&& rm -rf <em>var_lib_apt_lists/* \
&& curl -sL https://deb.nodesource.com/setup_10.x | bash - \
&& apt install nodejs \
&& rm -rf _usr_lib_systemd</em>* \
&& apt-get purge -y --auto-remove $buildDeps \
&& ln -s _usr_local_bin_node _usr_local_bin_nodejs \
&& node -v
## Kopiujemy pliki .csproj i .sln  aby pobrać wszystkie  zależności z nugeta
COPY *.sln .

COPY LifeLike.Web_<em>.csproj .<em>LifeLike.Web/
COPY LifeLike.Test</em></em>.csproj .<em>LifeLike.Test/
COPY LifeLike.Data</em><em>.csproj .<em>LifeLike.Data/
COPY LifeLike.Repositories</em></em>.csproj ._LifeLike.Repositories/

RUN dotnet restore

## A teraz kopiujemy wszystkie pliki i budujemy  nasz webowy projekt pod konfiguracje “publish” (buduje  wtedy dll i pre renderuje projekt angularowy pod produkcję)
COPY . .
WORKDIR _app_LifeLike.Web
RUN dotnet publish -c Release -o /out

## A teraz kopiujemy do  folderu out i oznaczamy, którą dll ma odpalić nasz kestrel.

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime
WORKDIR /out
COPY --from=build /out .
ENTRYPOINT ["dotnet", "LifeLike.Web.dll"]

Łatwe? Teraz już napewno. Można już użyć docker build, a potem nawet i docker push, by wrzucić na cloud docker nasz obraz. Można też skonfigurować budowanie naszego obrazu tutaj Docker Cloud – Build, Ship and Run any App, Anywhere Tzn. można, o ile mamy nasz projekt na jakimś zewnętrznym repozytorium, jak np. w moim przypadku github.

Docker Compose

Docker dostał ciekawe rozszerzenie przyjazne jeszcze szybszemu “deploymentowi” i zostało ono przyjacielem dev opsów i jest za darmo do pobrania. Jak dla mnie to jedna z 3 rzeczy, które są ważne do pobrania na nowym sprzęcie.

1. to docker

2. docker-compose

3. git (Chyba, że trzymamy pliki konfigurację do produkcji oraz docker-compose na jakimś prywatnym serwerze lub chmurze).


Procedurę instalacji docker compose znajdziecie na Install Docker Compose | Docker Documentation i jest ona przystosowana pod wiele platform.
Poza naszym serwisem, kolejną kluczową rzeczą jest konfiguracja nginx, który kieruje ruchem, portami oraz zarządza certyfikatami i zabezpieczeniami.

Polecam, bez względu jakiej technologii używamy (nawet i php). Zarządza także przeniesieniem na https.
Poniższy listing jest przykładem dla mojego serwisu na https://lifelike.pl :

version: '3.7'
services:
web:     # Tu konfigurujemy, jaki obraz albo skąd brać Dockerfile, aby skonfigurować serwer web.
image:  aluspl/lifelike:latest
# build:
# context: .
ports: # Porty jakie używamy   na wejściu  i do jakich mamy  kierować na zewnątrz
- 5000:80
- 44394:443
volumes: # Tu  przekierowujemy  konkretne foldery i pliki.
- ./app.settings.json:/out/app.settings.json
# - ./lifelike.db:/out/lifelike.db:rw
- /etc/letsencrypt/live/lifelike.pl:/out/certs

proxy: # Konfiguracja nginx,  czyli nasz reserve proxy
image:  nginx:latest
ports:
- 80:80
- 443:443
volumes:  # Przekierowanie  lokalnej konfiguracji do nginx oraz logów
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./logs:/var/log/nginx:rw
##  Lets Encrypt - ścieżka do certyfikatu na naszym systemie
- /etc/letsencrypt:/etc/letsencrypt:rw
- ./www:/var/www/letsencrypt
links:  #  Połączenie z konkretnym serwisem (w konfingu nginx,  #web jest widoczny jako web a nie localhost)
-  web
restart: always

Po tym wszystkim wystarczy odpalić docker-compose up (build jeśli zmieniamy coś w dockerze, który lokalnie budujemy) lub docker-compose down, aby zamknąć i usunąć kontenery.

I pamiętajcie o najważniejszym. Rzeczy w dockerze czyszczą się po update obrazu, dlatego tak kluczowe jest użycie volumes, co przynajmniej pozwoli zachować pliki lokalnie. W app.settings np. nadpisałem inne klucze do JWT , oraz mam możliwość zamiany sqlite na connection string (jeśli używamy zewnętrznej bazy). Jest to chyba jeden z lepszych sposobów na wrzucenie tego samego kodu na produkcję w sposób bezpieczny i na open source.

Nginx – Reverse Proxy

O Nginx wspominałem już wcześniej, ale też wtedy miałem o nim znacznie mniejsze pojęcie. Dzięki Slackowej pomocy kolegi (thx Daniel), zrozumiałem znacznie więcej na temat konfiguracji oraz dodaniu ssl i innych zabezpieczeń do naszego serwisu.
Paradoksalnie konfiguracja Nginx jest całkiem łatwa i logiczna.

server {
# śledzenie portu 80 (domyślne http)
listen 80;
# przekierowanie potrzebne dla certyfikatw lets encrypt.  Taki wymóg  certyfikatu let’s encrypt
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
return 301 https://$host$request_uri;
}
server {
# jaki port ma śledzić (https)
listen 443 ssl;
# nazwa  domeny
server_name lifelike.pl;
  # Gdzie ma zapisywać
    access_log          /var/log/nginx/.access.log;
    error_log           /var/log/nginx/error.log;       
    # ścieżka do podpiętego w volume  certyfikatu ssl, o którym przeczytacie w następnym rozdziale. 
    ssl_certificate     /etc/letsencrypt/live/lifelike.pl/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/lifelike.pl/privkey.pem;
    # zabezpieczenie
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;
    # dodatkowe ustawienia na temat przekierowań
    location / {
        proxy_pass         http://web;
        proxy_redirect     off;
        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-Host $server_name;
    }
}

Wiadomo, że można jeszcze ustawić jak się chcę, a na frontendzie osobno wrzucić Angular/ React/ Vue czy co tam się chce, backend w osobnym dockerze, a dodatkowe usługi w jeszcze innych obrazach.

Let’s Encrypt

W pewnym momencie po skonfigurowaniu docker, podpięciu domeny stwierdziłem, że czegoś mi tu brakuje. Takiej ładnej kłódeczki, która pokazuję ludziom, że ta strona jest bezpieczna. Dzięki uprzejmości let’s encrypt, jest to teraz darmowe. Nie jest to jakaś konfiguracja łatwa, a dodatkowo wiem, że niektórzy wrzucają samego let’s encrypt jako kolejny obraz docker i podpinają ten sam volume co do Nginx (etc/letsencryptt oraz /var/www/letsencrypt). W moim przypadku zrobiłem to bardziej stacjonarnie.
Na produkcyjnym ubuntu server (VPS) zainstalowałem paczkę za pomocą komendy

sudo apt install python-certbot-apache

A następnie po zainstalowniu paczki, wygenerowałem klucz za pomocą

sudo  letsencrypt certonly --webroot \
--email email@email.pl --agree-tos \
-w /var/www/letsencrypt -d nazwadomeny.pl

Generalnie generujemy pliki *.pem, z aktualnym certyfikatem. Wygenerowany Certyfikat można użyć także w innych usługach, m.in do zewnętrznego logowania za pomocą Identity Server czy OAuth.
Jeśli macie lokalnie nginx albo apache, to komenda letsencrypt (lub certbot) umożliwia także bezpośrednią integrację z serwisami, ale polecam spojrzeć do dokumentacji 🙂
Potem tylko wejść na swoją stronę przez https://nazwadomeny.pl i możemy podziwiać nasze wypociny.
Jeśli skończy się certyfikat, można odnowić za pomocą letsencrypt —renew

Ładnie zabezpieczone 🙂 

DevOps for Dummies

To chyba już wszystko na temat lekkiego poradnika na temat postawienia swojej strony na dockerach. Powyższe przykłady można także użyć na obrazach Ubuntu Server na AWS, DigitalOcean czy gdziekolwiek chcecie, a jak chcecie wspomóc autora wpisu: https://m.do.co/c/a0ee3602fd94 Dostaniecie w pakiecie 10$ z tego linku (2 miesiące na najsłabszej, ale jednocześnie wciąż wydajnej maszynie) .
Jeśli macie jakieś pytania to w komentarzach, fanpage’u, a nawet i DevsPL Slack pod Nickiem AlusPL służę pomocą.
p.s Dzięki Daniel za pomoc z konfiguracją i dostarczeniem materiału pod ten wpis.