{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
    "<div class=\"alert alert-block alert-info\">\n",
    "<h1> Inżynieria uczenia maszynowego </h1>\n",
    "<h2> 4. <i>Konteneryzacja</i>  [laboratoria]</h2> \n",
    "<h3> Tomasz Ziętkiewicz (2022)</h3>\n",
    "</div>\n",
    "\n",
    "![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Plan na dziś\n",
    "\n",
    "1. Konteneryzacja i Docker\n",
    "2. Integracja Docker-Jenkins"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 1. Konteneryzacja\n",
    "- Konteneryzacja to metoda tworzenia lekkich, odizolowanych środowisk uruchomieniowych\n",
    "- Różnica między konteneryzacją a maszynami wirtualnymi:\n",
    "  - Wirtualizacja na poziomie systemu operacyjnego a nie sprzętu\n",
    "  - Konteneryzacja jest lżejsza: kontener używa tego samego jądra (kernel) co system hosta - mniejszy narzut\n",
    "  - Konteneryzacja zapewnia gorszy stopień izolacji od hosta\n",
    "  - Dzięki dostępnym narzędziom i infrastrukturze kontenery są łatwiejsze w utrzymywaniu i bardziej przenośne\n",
    "- Ułatwiają:\n",
    "  - rozwój,\n",
    "  - uruchamianie\n",
    "  - i dostarczanie\n",
    "aplikacji.\n",
    "- Konteneryzacja to nie tylko Docker:\n",
    "  - chroot\n",
    "  - Solaris Containers\n",
    "  - LXC (Linux Containers)\n",
    "  - OpenVZ\n",
    "  - Windows containers\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 1.1 Docker\n",
    "- Najpopularniejszy obecnie system konteneryzacji\n",
    "- Działa w m.in. na systemach Linux, Windows i Max OS\n",
    "- Udostępnia narzędzia i serwisy ułatwiające korzystanie, zarządzanie i dzielenie się kontenerami\n",
    "- Docker umożliwia stworzenie paczki zawierającej sam program jak i środowisko, w którym ma być on uruchomiony\n",
    "  \n",
    "- Dokumentacja: https://docs.docker.com/get-started/\n",
    "</br><img style=\"height: 50px;\" src=\"img/environments/docker.png\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 1.1 Terminologia\n",
    " - *Container* (kontener) - instancja obrazu. Może być uruchomiona, zatrzymana. Stan kontenera można zapisać tworząc nowy obraz. Uruchomienie kontenera zazwyczaj zajmuje mało czasu.\n",
    " - *Image* (obraz) - niezmienny (readonly) przepis na stworzenie kontenera. Obrazy można ściągnąć lub udostępnić za pośrednictem *rejestru*. Budowanie obrazu trwa zazwyczaj długo.\n",
    " - *Dockerfile* - plik tekstowy zawierający przepis na zbudowanie obrazu\n",
    " - *Docker registry* - rodzaj repozytorium, przechowującego obrazy dockera\n",
    " - *Docker Hub* - publiczne *Docker registry*, z którego każdy może pobrać potrzebne mu obrazy oraz publikować swoje"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 1.2 Jak zacząć?\n",
    " - Na komputerach w laboratoriach: https://laboratoria.wmi.amu.edu.pl/en/issues/docker/\n",
    " - Lokalnie: [instalacja](https://docs.docker.com/engine/install/)\n",
    " - Możliwa zarówno pod Linux, Windows i MacOS.\n",
    " - Kontenery Linuxowe można uruchamiać również pod Windowsem (za pomocą Docker Desktop lub WSL 2 (Windows Subsystem for Linux). Pod spodem oba używają maszyny wirtualnej (Hyper-V) z Linuxem, w której uruchamiane są kontenery [link](https://www.docker.com/blog/docker-hearts-wsl-2/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 1.3 Podstawowe polecenia\n",
    "- ```docker help [polecenie]``` - wyświetla listę dostępnych poleceń dockera lub opis podanego polecenia. Rozbudowana dokumentacja poleceń: https://docs.docker.com/engine/reference/commandline/docker/\n",
    "- ```docker run``` - uruchamia istniejący obraz tworząc kontener. Przykładowe wywołania:\n",
    "  - ```docker run -i -t ubuntu```<br>\n",
    "  Uruchamia kontener z obrazu \"ubuntu\", allokuje terminal (`-t`) i ustawia tryb \"interaktywny\" (`-i`), dzięki czemu dostajemy terminal \"wenątrz\" kontenera i możemy wywoływać w nim polecenia\n",
    "\n",
    "  - ```docker run -p 8080:8080 jenkins/jenkins:lts```<br>\n",
    "  Uruchomi kontener z Jenkinsem, w wersji \"LTS\". Jeśli obraz Jenkins nie był wcześniej zbudowany/pobrany na lokalną maszynę, automatycznie zostanie pobrany z [Docker Hub](https://hub.docker.com/r/jenkins/jenkins).\n",
    "  Port 8080 konenera zostanie powiązany z portem 8080 hosta. Dzięki temu będziemy mogli w przeglądarce dostać się do Jenkinsa pod adresem http://localhost:8080\n",
    "- ```docker build [OPTIONS] PATH | URL | -``` - buduje obraz na podstawie pliku Dockerfile i kontekstu (plików dostępnych podczas budowania). Przykład:<br>\n",
    "  - ```docker build -t tzietkiewicz/helloworld:1.0 .```<br>\n",
    "  buduje obraz przekazując bieżący katalog (`.`) jako kontekst i korzystając z pliku Dockerfile znajdującego się tamże. Obraz zostanie otagowany (`-t`) tagiem `tzietkiewicz/helloworld` z wersją `1.0`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "- ```docker images``` - listuje dostępne lokalnie obrazy\n",
    "- ```docker ps``` - listuje uruchomione/zatrzymane kontenery\n",
    "- ```docker stop CONTAINER_ID``` - zatrzymuje kontener. Uruchomione w nim procesy zostają wyłączone (`SIGTERM` -> `SIGKILL`)\n",
    "- ```docker start CONTAINER_ID``` - uruchamia ponownie kontener\n",
    "- ```docker system df``` - pokazuje miejsce zajęte przez obrazy, kontenery i woluminy\n",
    "- ```docker system prune``` - usuwa nieużywane obrazy i kontenery, zazwyczaj zwalniając sporo miejsca na dysku"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 1.4 Interakcja/komunikacja z kontenerem\n",
    " - Poprzez terminal\n",
    " - Poprzez `docker exec` - wywołanie polecenia w działającym kontenerze\n",
    " - Poprzez port zmapowany przez flagę `-p` (np. REST API albo interfejs w przegląrce)\n",
    " - Przez system plików: \n",
    "   - bind mount: podmontowanie katalogów hosta w kontenerze poprzez flagę `-v` [dokumentacja](https://docs.docker.com/engine/reference/commandline/run/#mount-volume--v---read-only)\n",
    "   - volumes: https://docs.docker.com/storage/volumes/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Zadanie 1 [na zajęciach]\n",
    "1. Zainstaluj Docker (lub skorzystaj z https://laboratoria.wmi.amu.edu.pl/en/issues/docker/)\n",
    "2. Uruchom obraz `ubuntu` w trybie interaktywnym z terminalem (`docker run -ti ubuntu`)\n",
    "\n",
    "Poniższe punkty wywołujemy wewnątrz kontenera (w otwartym właśnie terminalu):\n",
    "\n",
    "3. Jaka wersja Ubuntu działa w kontenerze? (polecenie `cat /etc/issue`)\n",
    "4. Jaki użytkownik wywołuje polecenia? (polecenie `whoami`)\n",
    "5. Jaki jest bieżący katalog? (polecenie `pwd`)\n",
    "5. Jaki procesor jest widoczny w środku kontenera? Czy jest to procesor Twojej maszyny? (`lscpu`)\n",
    "6. Ile wolnego miejsca na dysku jest widoczne wewnątrz kontenera (`df -h`)? Czy jest to zgodne z tym, co pokazuje maszyna hosta?\n",
    "7. Sprawdź ile dostępnej pamięci RAM widać w konenerze (`free -h`). Czy zgadza się to z wynikiem na maszynie hosta?\n",
    "8. Spróbuj uruchomić jedno z popularnych narzędzi Linuksowych, dostępnych na maszynie hosta (np. `vim`, `less`, `htop`). Czy udało się je uruchomić?\n",
    "9. Zainstaluj w kontenerze jedno z brakujących narzędzi, np: `apt update; apt install htop`\n",
    "10. Uruchom następujące polecenie: <br>\n",
    "`while true; do date > time.log; sleep 1; done`\n",
    "będzie ono co sekundę zapisywać bieżący timestamp w pliku time.log\n",
    "\n",
    "Poniższe polecenia wykonujemy na zewnątrz kontenera (otwórz w tym celu nową konsolę):\n",
    "\n",
    "11. Sprawdź ID uruchomionego kontenera (`docker ps`) i zatrzymaj go (`docker stop`)\n",
    "12. Sprawdź co się stało w oknie z konsolą kontenera\n",
    "13. Uruchom kontener jeszcze raz (`docker start`). Gdzie jest nasza konsola?!!\n",
    "14. Żeby otrzymać konsolę, wykonaj jedno z poniższych:\n",
    "    - zatrzymaj kontener i uruchom jeszcze raz z flagą `-i`\n",
    "    - uruchom polecenie \"bash\" w kontenerze za pomocą polecenia `docker exec -ti CONTAINER_ID bash`  - pozwala ono uruchomić dowolne polecenie w działającym kontenerze.\n",
    "15. Czy polecenie `while true; do date > time.log; sleep 1; done` wciąż działa? Sprawdź ostatni timestamp zapisany do pliku `time.log`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 1.4 Dockerfile\n",
    "\n",
    " - Dokumentacja: https://docs.docker.com/engine/reference/builder/\n",
    "\n",
    " - Dockerfile składa się z serii poleceń.\n",
    " - Polecenia dockera są pisane WIELKIMI LITERAMI\n",
    " - Wywołanie każdego polecenia tworzy nową warstwę (*layer*)\n",
    " - Jeśli zbudowaliśmy obraz a potem zmieniliśmy jedno z poleceń / dodaliśmy nowe, to przebudowane zostaną tylko warstwy od zmienionej w dół (osczędność czasu i zasobów)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Przykładowy Dockerfile:\n",
    "```Dockerfile\n",
    "# Nasz obraz będzie dzidziczył z obrazu Ubuntu w wersji latest\n",
    "FROM ubuntu:latest\n",
    "\n",
    "# Instalujemy niezbędne zależności. Zwróć uwagę na flagę \"-y\" (assume yes)\n",
    "RUN apt update && apt install -y figlet\n",
    "\n",
    "# Stwórzmy w kontenerze (jeśli nie istnieje) katalog /app i przejdźmy do niego (wszystkie kolejne polecenia RUN, CMD, ENTRYPOINT, COPY i ADD będą w nim wykonywane)\n",
    "WORKDIR /app\n",
    "\n",
    "# Skopiujmy nasz skrypt do katalogu /app w kontenerze\n",
    "COPY ./figlet-loop.sh ./\n",
    "\n",
    "# Domyślne polecenie, które zostanie uruchomione w kontenerze po jego starcie\n",
    "CMD ./figlet-loop.sh\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Zawartość pliku `figlet-loop.sh`:\n",
    "```bash\n",
    "#!/bin/bash\n",
    "while read line; do\n",
    "\tfiglet \"$line\"\n",
    "done\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Budujemy obraz:\n",
    "```bash\n",
    "docker build -t figlet-loop .\n",
    "```\n",
    "\n",
    "```\n",
    "Sending build context to Docker daemon  3.072kB\n",
    "Step 1/5 : FROM ubuntu:latest\n",
    " ---> 94e814e2efa8\n",
    "Step 2/5 : RUN apt update && apt install -y figlet\n",
    "\n",
    " ---> Running in ba8b14deeeca\n",
    "Get:1 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]\n",
    "[...]\n",
    "Get:18 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [1402 kB]\n",
    "Fetched 22.3 MB in 3s (8343 kB/s)\n",
    "Reading package lists...\n",
    "Building dependency tree...\n",
    "Reading state information...\n",
    "[...]\n",
    "Reading package lists...\n",
    "Building dependency tree...\n",
    "Reading state information...\n",
    "The following NEW packages will be installed:\n",
    "  figlet\n",
    "0 upgraded, 1 newly installed, 0 to remove and 50 not upgraded.\n",
    "Need to get 133 kB of archives.\n",
    "After this operation, 752 kB of additional disk space will be used.\n",
    "Get:1 http://archive.ubuntu.com/ubuntu bionic/universe amd64 figlet amd64 2.2.5-3 [133 kB]\n",
    "debconf: delaying package configuration, since apt-utils is not installed\n",
    "Fetched 133 kB in 0s (605 kB/s)\n",
    "Selecting previously unselected package figlet.\n",
    "(Reading database ... 4039 files and directories currently installed.)\n",
    "Preparing to unpack .../figlet_2.2.5-3_amd64.deb ...\n",
    "Unpacking figlet (2.2.5-3) ...\n",
    "Setting up figlet (2.2.5-3) ...\n",
    "update-alternatives: using /usr/bin/figlet-figlet to provide /usr/bin/figlet (figlet) in auto mode\n",
    "update-alternatives: warning: skip creation of /usr/share/man/man6/figlet.6.gz because associated file /usr/share/man/man6/figlet-figlet.6.gz (of link group figlet) doesn't exist\n",
    "Removing intermediate container ba8b14deeeca\n",
    " ---> 30470dc0bd47\n",
    "Step 3/5 : WORKDIR /app\n",
    " ---> Running in 47ca74217790\n",
    "Removing intermediate container 47ca74217790\n",
    " ---> 0f352dfc965d\n",
    "Step 4/5 : COPY ./figlet-loop.sh ./\n",
    " ---> 450ba60dc50d\n",
    "Step 5/5 : CMD ./figlet-loop.sh\n",
    " ---> Running in 38f83a71b1a9\n",
    "Removing intermediate container 38f83a71b1a9\n",
    " ---> c6d81a065621\n",
    "Successfully built figlet-loop:latest\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Uruchamiamy:\n",
    "```\n",
    "docker run -ti figlet-loop\n",
    "Hello World!\n",
    " _   _      _ _        __        __         _     _ _ \n",
    "| | | | ___| | | ___   \\ \\      / /__  _ __| | __| | |\n",
    "| |_| |/ _ \\ | |/ _ \\   \\ \\ /\\ / / _ \\| '__| |/ _` | |\n",
    "|  _  |  __/ | | (_) |   \\ V  V / (_) | |  | | (_| |_|\n",
    "|_| |_|\\___|_|_|\\___/     \\_/\\_/ \\___/|_|  |_|\\__,_(_)\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Zamiast domyślnego polecenia (`figlet-loop.sh`) uruchommy bash, żeby sprawdzić, co jest w naszym kontenerze:\n",
    "```bash\n",
    "docker run -ti figlet-loop:latest bash\n",
    "root@a44c68ce835e:/app# pwd\n",
    "/app\n",
    "root@a44c68ce835e:/app# ls -l\n",
    "total 4\n",
    "-rwxrwxr-x 1 root root 53 Mar 28 22:33 figlet-loop.sh\n",
    "root@a44c68ce835e:/app# \n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Zadanie 2. [10 pkt]\n",
    "1. Napisz prosty Dockerfile, który zdefinuje środowisko potrzebne do wywołania poleceń stworzonych na zajęciach \"2. Dane\". Przypuszczalnie wystarczy, że zainstalujesz zależności takie jak kaggle czy pandas, np: \n",
    "```bash\n",
    "pip install --user kaggle\n",
    "pip install --user pandas\n",
    "```\n",
    "Niech zdefiniowany przez Ciebie obraz dziedziczy z jakiegoś popoularneg obrazu, np. `ubuntu`\n",
    "Umieść Dockerfile w głównym katalogu repozytorium ze skryptami stworzonymi na zajęciach 2.\n",
    "\n",
    "2. Zbuduj obraz korzystając z polecenia `docker build .`\n",
    "   Na końcu otrzymasz id obrazu, który powstał\n",
    "3. Uruchom kontener z terminalem `docker run -ti IMAGE_ID` podając ID obrazu, które otrzymałeś w poleceniu 2.\n",
    "4. Spróbuj uruchomić jeden z twoich skryptów w kontenerze. Jeśli brakuje jakiś zależności: możesz spróbować zainstalować je interaktywnie w konsoli. W ten sposób będziesz wiedział jakie polecenia dodać do Dockerfile.\n",
    "5. Plik Dockerfile dodaj do repozytorium\n",
    "6. Utwórz bezpłatne konto na https://hub.docker.com/\n",
    "7. Po zalogowaniu stwórz nowe repozytorium (https://hub.docker.com/repository/create), możesz nazwać je np. `ium`\n",
    "8. W ustawieniach docker hub wygeneruj \"Access token\" (https://hub.docker.com/settings/security)\n",
    "9. Uruchom `docker login --username TWÓJ_DOCKER_ID` i podaj stworzony w poprzednim kroku \"Access token\"\n",
    "10. Dodaj tag do obrazu stworzonego 2 punkcie 3. Dzięki temu będzie można go opublikować: `docker tag IMAGE_ID TWÓJ_DOCKER_ID/ium:NUMER_WERSJI`. Mogliśmy otagować obraz na etapie jego budowania (flaga `-t`), ale wtedy nie znaliśmy jeszcze nazwy użytkownika i repozytorium z Docker Hub.\n",
    "11. Teraz możesz wypchnąć swój otagowany obraz do repozytorium: `docker push TWÓJ_DOCKER_ID/ium:NUMER_WERSJI`\n",
    "12. Twój obraz powinien być widoczny na Docker Hub. Inni mogą go teraz znaleźć na [Docker Hub](https://hub.docker.com/search?q=&type=image), np.:<br>\n",
    "https://hub.docker.com/r/tzietkiewicz/ium <br>\n",
    "oraz uruchomić wywołując: `docker run TWÓJ_DOCKER_ID/ium:NUMER_WERSJI`, np.:<br>\n",
    "```docker run tzietkiewicz/ium```\n",
    "13. Link do obrazu w Docker Hub wklej do arkusza ze zbiorami danych [link](https://uam.sharepoint.com/:x:/s/2021SL06-DIUMUI0LABInynieriauczeniamaszynowego-Grupa11/EYhZK_aXp41BsIVS4K-L1V4B_vM2FjO5nJZMWv2QKXJolA?e=DKIS2O)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 2. Integracja Docker-Jenkins"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 2.1 Jenkins\n",
    "Jenkins może działać na wielu systemach operacyjnych:\n",
    " - Linux\n",
    " - Windows\n",
    " - MacOS"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 2.1 Jenkins - Terminologia (https://www.jenkins.io/doc/book/glossary/):\n",
    " - **Controller**: The central, coordinating process which stores configuration, loads plugins, and renders the various user interfaces for Jenkins\n",
    " - **Agent**: An agent is typically a machine, or container, which connects to a Jenkins controller and executes tasks when directed by the controller\n",
    " - **Master**: A deprecated term, synonymous with Controller.\n",
    " - **Node**: A machine which is part of the Jenkins environment and capable of executing Pipelines or Projects. Both the Controller and Agents are considered to be Nodes.\n",
    " - **Executor**: A slot for execution of work defined by a Pipeline or Project on a Node. A Node may have zero or more Executors configured which corresponds to how many concurrent Projects or Pipelines are able to execute on that Node."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Główna instancja Jenkinsa (tzw. *Controller* aka. *Master*) może mieć podłączonych kilka węzłów (\"nodes\") typu \"slave\".\n",
    " - *Controller* jest odpowiedzialny za interakcję z użytkownikiem, rozdzielanie zadań dla między agentów\n",
    " - Zadania (\"builds\") są wykonywane na jednym z \"Agentów\". Node, na którym jest uruchomiony \"Controller\" może działać również jako \"Agent\"\n",
    " - Każdy węzeł może działać pod kontrolą innego systemu operacyjnego. Dzięki temu możemy wykonywać zadania (albo ich części) w różnych środowiskach\n",
    " <img style=\"height: 300px;\" src=\"IUM_04/master-slave.png\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    " - Do definiowana gdzie może być wykonana dana część pipeline, służy sekcja [agent / node](https://www.jenkins.io/doc/book/pipeline/syntax/#agent). Poniższy kod wywoła sie tylko na węźle/węzłach \"myAgent\":\n",
    " ```groovy\n",
    " node(\"myAgent\") {\n",
    "     stage(\"One\"){\n",
    "         echo 'hello'\n",
    "     }\n",
    "}\n",
    " ```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    " ## 2.2 Docker w Jenkins\n",
    " <img style=\"height: 100px;\" src=\"IUM_04/docker-jenkins.png\"/></b>\n",
    "\n",
    "  - Jenkins posiada wygodną intergrację z Dockerem \n",
    "  - Umożliwia ona uruchamianie kroków (steps) wewnątrz kontera\n",
    "  - Obrazy mogą być automatycznie pobrane albo zbudowane na podstawie Dockerfile\n",
    "  - Więcej informacji: https://www.jenkins.io/doc/book/pipeline/docker/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 2.2 Przykłady pipeline\n",
    "Używanie gotowego obrazu:\n",
    "  - Scrippted pipeline:\n",
    "```groovy\n",
    "    node {\n",
    "        docker.image('ubuntu:latest').inside {\n",
    "            stage('Test') {\n",
    "                sh 'cat /etc/issue'\n",
    "            }\n",
    "        }\n",
    "   }\n",
    "```\n",
    "  - Declarative:\n",
    "    ```groovy\n",
    "    pipeline {\n",
    "        agent {\n",
    "            docker { image 'ubuntu:latest' }\n",
    "        }\n",
    "        stages {\n",
    "            stage('Test') {\n",
    "                steps {\n",
    "                    sh 'cat /etc/issue'\n",
    "                }\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 2.2 Przykłady pipeline\n",
    "Budowanie obrazu z Dockerfile:\n",
    "  - Scrippted pipeline:\n",
    "  ```groovy\n",
    "    node {\n",
    "        checkout scm\n",
    "        //Pierwszy argument to tag, który zostania nadany zbudowanemu obrazowi\n",
    "        //Jeśli chcemy użyć Dockerfile z innej ścieżki niż ./Dockerfile, możemy ją podać jako drugi argument\n",
    "        def testImage = docker.build(\"test-image\", \"./dockerfiles/test\") \n",
    "\n",
    "        //Wszystkie polecenia poniżej wykonają się w kontenerze, z podmontowanym Workspace Jenkinsa\n",
    "        testImage.inside {\n",
    "            sh 'make test'\n",
    "        }\n",
    "    }\n",
    "```\n",
    "  - Declarative:\n",
    "    ```groovy\n",
    "  pipeline {\n",
    "    agent { \n",
    "        dockerfile true \n",
    "    }\n",
    "    stages {\n",
    "        stage('Test') {\n",
    "            steps {\n",
    "                sh 'cat /etc/issue'\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Zadanie 3. [5 pkt]\n",
    "1. Zmodyfikuj stworzony na poprzednich (3.) zajęciach Jenkinsfile opisujący pipeline \"s123456-create-dataset\" tak, żeby wywoływać w nim skrypty stworzone na zajęciach 2., w środku kontenera stworzonego w zadaniu 2.<br> \n",
    "   Skorzystaj z mechanizmu tworzącego kontener bezpośrednio na Jenkinsie wprost z pliku Dockerfile.\n",
    "\n",
    "2. Zmodyfikuj stworzony na poprzednich (3.) zajęciach Jenkinsfile opisujący pipeline \"s123456-dataset-stats\" tak, żeby wywoływać w nim skrypty stworzone na zajęciach 2., w środku kontenera stworzonego w zadaniu 2.<br>\n",
    "   Skorzystaj z mechanizmu wykorzystującego gotowy obraz (lokalny, albo ściągany z Docker Hub)"
   ]
  }
 ],
 "metadata": {
  "author": "Tomasz Ziętkiewicz",
  "celltoolbar": "Slideshow",
  "email": "tomasz.zietkiewicz@amu.edu.pl",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "lang": "pl",
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  },
  "slideshow": {
   "slide_type": "slide"
  },
  "subtitle": "4.Konteneryzacja[laboratoria]",
  "title": "Inżynieria uczenia maszynowego",
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": false,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": false,
   "toc_window_display": false
  },
  "year": "2021"
 },
 "nbformat": 4,
 "nbformat_minor": 4
}