\documentclass[12pt,oneside,a4paper]{book} % Język polski \usepackage{amssymb} \usepackage{polski} \usepackage[polish]{babel} %Opcja dla edytorów kodujących polskie znaki w utf8 \usepackage[utf8]{inputenc} \usepackage{microtype} \usepackage{fancyhdr} \usepackage{pstricks} \usepackage{blindtext} \usepackage[T1]{fontenc} \usepackage{authblk} \usepackage{placeins} \usepackage{tocloft} \usepackage{hyperref} \usepackage{listings} \usepackage{chngcntr} \usepackage{lmodern} \usepackage{pstricks} \usepackage{enumitem} \usepackage{xcolor} \lstset{basicstyle=\ttfamily, showstringspaces=false, commentstyle=\color{red}, keywordstyle=\color{blue} } % Włączenie wcięcia w pierwszym akapicie \usepackage{indentfirst} % Możliwość dodwania obrazków \usepackage{graphicx} % Zmiana nazwy bib \def\bibname{Literatura} %\DisableLigatures{encoding = *, family = * } % Wyłączenie countowania img po chapterze. \usepackage{chngcntr} \counterwithout{figure}{chapter} % Zmiana rozkładu lini w dokumencie \linespread{1.3} \renewcommand*{\lstlistingname}{\textbf{Kod}} \lstset{ basicstyle=\fontsize{11}{13}\selectfont\ttfamily, columns=fullflexible, frame=single, breaklines=true, %postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space}, } %--------------- Wydruk jednostronny \fancyhead[C]{} \fancyfoot[C]{\thepage} \fancyhead[L]{\footnotesize\rightmark} \fancyhead[R]{} \renewcommand{\sectionmark}[1]{\markright{\thesection.\ #1}} \setcounter{secnumdepth}{3} \renewcommand*\thesection{\arabic{section}} \renewcommand*\thesubsection{\arabic{section}.\arabic{subsection}} \renewcommand*\thesubsubsection{% \arabic{section}.\arabic{subsection}.\arabic{subsubsection}% } \setcounter{tocdepth}{3} \setcounter{secnumdepth}{3} \pagestyle{fancy} \begin{document} %\maketitle \begin{titlepage} \centering \includegraphics[width=0.35\textwidth]{img/uam-logo.pdf}\par {\scshape\large Wydział Matematyki i Informatyki \par} \vspace{0.75cm} {\small Maciej Głowacki \\ Numer albumu: 434689\par} \vspace{0.2cm} {\small Filip Izydorczyk \\ Numer albumu: 434700\par} \vspace{0.2cm} {\small Marcin Woźniak \\ Numer albumu: 434812\par} \vspace{0.2cm} {\small Hubert Wrzesiński \\ Numer albumu: 434813\par} \vspace{1.5cm} {\large\bfseries PlanNaPlan - Dokumentacja wdrożeniowa} \vspace{0.7cm} \vfill % Bottom of the page Poznań, styczeń 2021 \end{titlepage} \thispagestyle{empty} \tableofcontents \newpage \section{Instalacja} \subsection{Backend} \subsubsection{Kompilowanie aplikacji ze źródła} \begin{itemize} \item \textbf{Krok 0:} Wymagania: \\ - System operacyjny: Linux \\ - Minimalna wersja: Java 14 \\ - Maven \\ - Baza Danych (np. MariaDB) \\ - Osobny user do uruchamiania aplikacji np. backend \item \textbf{Krok 1:} Pobranie repozytorium ze źródła: \begin{lstlisting}[ frame=single, numbers=none, ] % git clone http://git.plannaplan.pl/filipizydorczyk/backend.git \end{lstlisting} \item \textbf{Krok 2:} Zmiana środowiska backendowego na produkcyjne: \begin{lstlisting}[ frame=single, numbers=none, ] % echo "spring.profiles.active=prod" > restservice/src/main/resources/application.properties \end{lstlisting} \item \textbf{Krok 3:} Instalacja pluginów za pomocą \lstinline{maven}: \begin{lstlisting}[ frame=single, numbers=none, ] % mvn clean % mvn install \end{lstlisting} \item \textbf{Krok 4:} Kompilowanie środowiska: \begin{lstlisting}[ frame=single, numbers=none, ] % cd restservice % mvn clean package spring-boot:repackage \end{lstlisting} \item \textbf{Krok 5:} Utworzenie folderu oraz skopiowanie aplikacji: \begin{lstlisting}[ frame=single, numbers=none, ] % mkdir -p /opt/plannaplan-backend/logs % cp -rv restservice/target/*.jar /opt/plannaplan-backend/backend.jar \end{lstlisting} \item \textbf{Krok 6:} Dodanie pustej bazy danych, a także użytkownika dla backend'u. \item \textbf{Krok 7:} Samo uruchomienie aplikacji - wiąże się z ustawieniem zmiennych środowiskowych. Polecamy stworzenie skryptu w Bashu aby to wszytsko było przetrzymywane tylko w tym skrypcie. Przykładowy skrypt \ref{skryptBash}. \begin{lstlisting}[ language=bash, label=skryptBash, frame=single, numbers=left, caption={Skrypt uruchamiający backend aplikacji} ] #!/bin/sh SERVICE_NAME="PlanNaPlan Backend" DIR="/opt/plannaplan-backend" export PATH=$PATH:$JAVA_HOME/bin export PLANNAPLAN_MYSQL_DB_HOST="" export PLANNAPLAN_MYSQL_DB_PORT="" export PLANNAPLAN_MYSQL_DB="" export PLANNAPLAN_MYSQL_DB_USERNAME="" export PLANNAPLAN_MYSQL_DB_PASSWORD="" export PLANNAPLAN_EMAIL="" export PLANNAPLAN_EMAIL_HOST="" export PLANNAPLAN_EMAIL_PORT="" export PLANNAPLAN_EMAIL_USERNAME="" export PLANNAPLAN_EMAIL_PASSWORD="" export PLANNAPLAN_CONSUMER_KEY="" export PLANNAPLAN_CONSUMER_SECRET="" java -jar $DIR/backend.jar >> $DIR/log-$(/usr/bin/date -I).log 2>&1 echo $! > /tmp/sd-plananplan.pid \end{lstlisting} \item \textbf{Krok 8:} Uzupełnienie skryptu (nr. \ref{skryptBash}) swoimi danymi produkcyjnymi. \item \textbf{Krok 9:} Utworzenie serwisu, aby backend startował przy uruchomieniu serwera. \begin{lstlisting}[ language=bash, label=systemD, frame=single, numbers=left, caption={Deamon uruchamiający backend aplikacji.} ] [Unit] Description=PlanNaPlan Backend After=network.target [Service] Type=simple ExecStart="/opt/plannaplan-backend/plannaplan-backend.sh" WorkingDirectory=/opt/plannaplan-backend User=backend #WYBRANY USER W KROKU 0 Group=backend #WYBRANY USER W KROKU 0 Environment=PATH=$PATH:$JAVA_HOME/bin StartLimitInterval=30 [Install] WantedBy=multi-user.target \end{lstlisting} \item \textbf{Krok 10:} Przeładownie \lstinline{systemctl}: \begin{lstlisting}[ frame=single, numbers=none, ] % systemctl daemon-reload \end{lstlisting} \item \textbf{Krok 11:} W celu posiadania dodania certyfikatu do backendu keystore należy umieścić w \lstinline{/keys/keystore.p12} \item \textbf{Krok 12:} Włączenie aby aplikacja uruchamiała się przy starcie systemu oraz pierwsze jej uruchomienie, a także status: \begin{lstlisting}[ frame=single, numbers=none, ] % systemctl enable plannaplan-backend % systemctl start plannaplan-backend % systemctl status plannaplan-backend \end{lstlisting} \end{itemize} \subsubsection{Binarna wersja aplikacji} \label{sssec:num1} \begin{itemize} \item \textbf{Krok 0:} Wymagania: \\ - System operacyjny: Linux \\ - Minimalna wersja Java 14 \\ - Baza Danych (np. MariaDB) \\ - Osobny user do uruchamiania aplikacji np. backend \item \textbf{Krok 1:} Pobranie binarnej.\\ Wszytskie wersje binarane aplikacji znajdują się \url{https://git.plannaplan.pl/filipizydorczyk/backend} \item \textbf{Krok 2:} Utworzenie folderu oraz skopiowanie binarnej wersji aplikacji do folderu \lstinline{/opt/plannaplan-backend/} \item \textbf{Krok 3:} Dodanie pustej bazy danych, a także użytkownika dla backend'u. \item \textbf{Krok 4:} Samo uruchomienie aplikacji - wiąże się z ustawieniem zmiennych środowiskowych. Polecamy stworzenie skryptu w Bashu aby to wszytsko było przetrzymywane tylko w tym skrypcie. Przykładowy skrypt \ref{skryptBash}. \item \textbf{Krok 5:} Uzupełnienie skryptu (nr. \ref{skryptBash}) swoimi danymi produkcyjnymi. \item \textbf{Krok 6:} Utworzenie serwisu, aby backend startował przy uruchomieniu serwera. Przykładowy kod nr. \ref{systemD}. \item \textbf{Krok 7:} Przeładownie \lstinline{systemctl}: \begin{lstlisting}[ frame=single, numbers=none, ] % systemctl daemon-reload \end{lstlisting} \item \textbf{Krok 8:} W celu posiadania dodania certyfikatu do backendu keystore należy umieścić w \lstinline{/keys/keystore.p12} \item \textbf{Krok 9:} Włączenie aby aplikacja uruchamiała się przy starcie systemu oraz pierwsze jej uruchomienie, a także status: \begin{lstlisting}[ frame=single, numbers=none, ] % systemctl enable plannaplan-backend % systemctl start plannaplan-backend % systemctl status plannaplan-backend \end{lstlisting} \end{itemize} \subsection{Frontend} \subsubsection{Budowanie strony ze źródła} \label{sssec:num2} \begin{itemize} \item \textbf{Krok 0:} Wymagania: \\ - System operacyjny: Linux \\ - Yarn \\ - Httpd \\ -- Zainstalowany certyfikat SSL (np. Let's Encrypt \footnote{Strona Let's Encrypt: \url{https://letsencrypt.org/}}) \\ - Osobny user do uruchamiania aplikacji np. frontend \item \textbf{Krok 1:} Pobranie repozytorium ze źródła: \begin{lstlisting}[ frame=single, numbers=none, ] % git clone http://git.plannaplan.pl/y0rune/frontend.git \end{lstlisting} \item \textbf{Krok 2:} Dodanie zmiennej środowiskowej razem z adresem URL aplikacji backend: \begin{lstlisting}[ frame=single, numbers=none, ] % echo "REACT_APP_API_URL=https://wmi-backend.plannaplan.pl" > .env \end{lstlisting} \item \textbf{Krok 3:} Zainstalowanie pluginów za pomocą \lstinline{Yarn}: \begin{lstlisting}[ frame=single, numbers=none, ] % yarn \end{lstlisting} \item \textbf{Krok 4:} Zbudowanie statycznej strony: \begin{lstlisting}[ frame=single, numbers=none, ] % yarn run build \end{lstlisting} \item \textbf{Krok 5:} Skopiowanie plików z folderu \lstinline{build/} do lokalizacji strony w \lstinline{Httpd} (np. \lstinline{/var/www/plannaplan.pl}) \item \textbf{Krok 6:} Przykładowa konfiguracja (Kod nr. \ref{apacheKonf}) \lstinline{Httpd} dla statycznej strony w katalogu \lstinline{/var/www/plannaplan.pl}. \begin{lstlisting}[ language=bash, label=apacheKonf, frame=single, numbers=left, caption={Konfiguracja statycznej strony w Httpd.} ] RewriteEngine on RewriteCond %{SERVER_NAME} = #URL DO STRONY RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] SSLEngine on ServerName #URL DO STRONY :443 DocumentRoot /var/www/plannaplan.pl/ ServerAdmin #EMAIL ADMINISTRATORA SSLCertificateFile /etc/letsencrypt/live/full.plannaplan.pl/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/full.plannaplan.pl/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf Options Indexes FollowSymLinks MultiViews AllowOverride All Allow from all Options -Indexes \end{lstlisting} \item \textbf{Krok 7:} Restart \lstinline{Httpd} za pomocą \lstinline{systemctl} \begin{lstlisting}[ frame=single, numbers=none, ] % systemctl httpd restart \end{lstlisting} \end{itemize} \newpage \section{Wdrożenie aplikacji} \subsection{Pierwsze ręczne wdrożenie} Każdy z naszych serwisów czyli Backend, Frontend, Baza Danych zostały wdrożone do serwerów, które znajdują się w chmurze Google Cloud Platform\footnote{Chmura Google: \url{https://cloud.google.com}}. Dodatkowo ze względów bezpieczeństwa ruch jest przekierowany przez serwer Proxy. \begin{figure}[hbt!] \centering \includegraphics[width=0.8\textwidth]{img/infra.pdf} \caption{Infrastruktura naszej aplikacji} \footnotesize{Źródło: Opracowanie własne} \label{fig:infra} \end{figure} \subsubsection{Proxy} Serwer znajduje się w chmurze Vultr\footnote{Chmura Vultr: \url{https://www.vultr.com/}}. Pełni on role serwera proxy \footnote{Definicja serwera proxy. Link: \url{https://en.wikipedia.org/wiki/Proxy_server} }. \vspace{5px} Informacje o serwerze: \begin{itemize}[noitemsep] \item 1vCPU \item 1 GB pamięci RAM \item 25 GB pojemność dysku \item System Operacyjny: Gentoo Linux \footnote{Strona główna dystrybucji: \url{https://gentoo.org}} \item Lokalizacja: Frankfurt, Niemcy \end{itemize} \subsubsection{Backend} Wdrożenie backendu aplikacji odbywało się podobnie jak to zostało opisane w podrozdziale \ref{sssec:num1}. \vspace{5px} Informacje o serwerze: \begin{itemize}[noitemsep] \item 2vCPU \item 2 GB pamięci RAM \item 20 GB pojemność dysku \item System Operacyjny: CentOS 8 \item Lokalizacja: Frankfurt, Niemcy \end{itemize} \subsubsection{Frontend} Wdrożenie frontendu aplikacji odbywało się podobnie jak to zostało opisane w podrozdziale \ref{sssec:num2}. \vspace{5px} Informacje o serwerze: \begin{itemize}[noitemsep] \item 1vCPU \item 600 MB pamięci RAM \item 20 GB pojemność dysku \item System Operacyjny: CentOS 8 \item Lokalizacja: Frankfurt, Niemcy \end{itemize} \subsubsection{Baza danych} Wdrożenie bazy danych (MariaDB\footnote{Strona projektu MariaDB \url{https://mariadb.org/}} w naszym przypadku) polegało na zainstalowaniu jej na osobnej maszynie. \vspace{5px} Informacje o serwerze: \begin{itemize}[noitemsep] \item 2vCPU \item 1.7 GB pamięci RAM \item 20 GB pojemność dysku \item System Operacyjny: CentOS 8 \item Lokalizacja: Frankfurt, Niemcy \end{itemize} \subsection{Automatyzacja wdrożenia na produkcje} Z powodu dość czasochłonnej każdorazowej zmiany na produkcję, doszliśmy do wniosku, że automatyzacja jest czymś koniecznym w naszym projekcie. Gdy odbywają się prace, które mają na celu poprawę aplikacji, każda taka zmiana odbywa się na osobnej gałęzi (branchu). Następnie, osoba wykonująca zmianę prosi o zmianę (w Pull Request) a kolejna osoba sprawdza czy wszystkie testy przechodzą na lokalnej maszynie użytkownika. W dalszym kroku akceptuje zmiany a następnie repozytorium klonowane jest do kilku instancji (GitLab, GitHub, Gitea) w celu zapasowej oraz przeprowadzenia kompilacji i wdrożenie jej na wybrany serwis. \subsubsection{Backend} Automatyzacja backendu odbywa się w kilku krokach: \begin{itemize} \item {build - aplikacja jest kompilowana, jeżeli wszytsko przejdzie zgodnie z planem CI/CD uruchamia kolejny krok.} \item {deploy\_production - binarny plik jest wysyłany do serwera, serwis \lstinline{plannaplan-backend} jest restartowny. W celu przeładowania aplikacji.} \end{itemize} \begin{lstlisting}[ label=backendYaml, frame=single, numbers=left, caption={Konfiguracja CI/CD backendu} ] stages: - build - deploy build: stage: build image: maven script: - echo "Start building App" - echo "spring.profiles.active=prod" > restservice/src/main/resources/application.properties - mvn clean - mvn install - cd restservice - mvn clean package spring-boot:repackage - echo "Build successfully!" artifacts: expire_in: 1 hour paths: - restservice/target/ only: - master deploy_production: stage: deploy before_script: - apt-get update - apt-get --yes --force-yes install rsync script: - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - eval $(ssh-agent -s) - ssh-add <(echo "$SSH_PRIVATE_KEY") - mkdir -p ~/.ssh - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' - echo "Deploying to server" - ssh backend@wmi-backend-gc.plannaplan.pl -t "sudo systemctl stop plannaplan-backend" - ssh backend@wmi-backend-gc.plannaplan.pl -t "rm -rf /opt/plannaplan-backend/backend.jar" - rsync --progress restservice/target/*.jar backend@wmi-backend-gc.plannaplan.pl:/opt/plannaplan-backend/backend.jar - sleep 5 - ssh backend@wmi-backend-gc.plannaplan.pl -t "sudo systemctl start plannaplan-backend" - echo "Deployed" only: - master \end{lstlisting} \subsubsection{Frontend} \begin{itemize} \item {build - aplikacja jest kompilowana, jeżeli wszytsko przejdzie zgodnie z planem CI/CD uruchamia kolejny krok.} \item {deploy\_production - statyczna strona wysyłana do serwera, serwis \lstinline{httpd} jest restartowny. W celu przeładowania aplikacji.} \end{itemize} \begin{lstlisting}[ label=backendYaml, frame=single, numbers=left, caption={Konfiguracja CI/CD frontendu} ] stages: - build - deploy build: stage: build image: node script: - echo "Start building App" - echo "REACT_APP_API_URL=https://wmi-backend.plannaplan.pl" > .env - yarn - CI= yarn run build - echo "Build successfully!" artifacts: expire_in: 1 hour paths: - build - node_modules/ deploy_production: stage: deploy before_script: - apt-get update - apt-get --yes --force-yes install rsync script: - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - eval $(ssh-agent -s) - ssh-add <(echo "$SSH_PRIVATE_KEY") - mkdir -p ~/.ssh - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' - echo "Deploying to server" - rsync --progress -r build/* --delete website@wmi-frontend.plannaplan.pl:/var/www/plannaplan.pl - echo "Deployed" only: - master \end{lstlisting} \end{document}