{"id":27091765,"url":"https://github.com/dgame/docker-tutorial","last_synced_at":"2026-02-16T19:03:38.263Z","repository":{"id":150593536,"uuid":"355278510","full_name":"Dgame/docker-tutorial","owner":"Dgame","description":null,"archived":false,"fork":false,"pushed_at":"2021-06-16T14:58:49.000Z","size":3942,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-11T22:35:00.675Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dgame.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-04-06T17:39:48.000Z","updated_at":"2023-03-05T03:25:22.000Z","dependencies_parsed_at":"2023-06-11T15:31:17.660Z","dependency_job_id":null,"html_url":"https://github.com/Dgame/docker-tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Dgame/docker-tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dgame%2Fdocker-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dgame%2Fdocker-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dgame%2Fdocker-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dgame%2Fdocker-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dgame","download_url":"https://codeload.github.com/Dgame/docker-tutorial/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dgame%2Fdocker-tutorial/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29515541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T18:37:19.720Z","status":"ssl_error","status_checked_at":"2026-02-16T18:36:46.920Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-06T07:53:35.764Z","updated_at":"2026-02-16T19:03:38.253Z","avatar_url":"https://github.com/Dgame.png","language":"Dockerfile","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\nmarp: true\n---\n\n# Roadmap\n\n - Docker: Kurzer Überblick\n - docker-compose\n - Dockerfile\n - Localstack: Überblick\n - aws-cli: Grundlagen\n - Localstack: Beispiel\n\n---\n\n# Docker\n\n![Docker Virtualisierung](Docker-linux-interfaces.svg.png)\n\n**Quelle**: [Wikipedia: Docker](https://de.wikipedia.org/wiki/Docker_(Software))\n\n---\n\n# Docker\n\n\u003e Docker dient zur Isolierung von Anwendungen mit Hilfe von sogenannter _Containervirtualisierung_. _Containervirtualisierung_ ist eine Methode um mehrere Instanzen eines Betriebssystems isoliert voneinander den Kernel eines Hostsystems nutzen zu lassen. [...]\n\n**Quellen**\n[Wikipedia: Docker](https://de.wikipedia.org/wiki/Docker_(Software))\n[Wikipedia: Containervirtualisierung](https://de.wikipedia.org/wiki/Containervirtualisierung)\n\n---\n\n## Docker: Begrifflichkeiten\n\n---\n\n### Image\nEin Speicherabbild eines Containers. Das _Image_ selbst besteht aus mehreren _Layern_, die schreibgeschützt sind und somit nicht verändert werden können. Ein _Image_ ist portabel, kann in Repositories gespeichert und mit anderen Nutzern geteilt werden. Aus einem _Image_ können immer mehrere _Container_ gestartet werden.\n\n**Quelle**\n[Wikipedia: Docker](https://de.wikipedia.org/wiki/Docker_(Software))\n\n---\n\n### Container\nAls _Container_ wird die aktive Instanz eines _Images_ bezeichnet. Der Container wird also gerade ausgeführt und ist beschäftigt. Sobald der _Container_ kein Programm ausführt oder mit seinem Auftrag fertig ist, wird der _Container_ automatisch beendet.\n\n**Quelle**\n[Wikipedia: Docker](https://de.wikipedia.org/wiki/Docker_(Software))\n\n---\n\n### Layer\nEin _Layer_ ist Teil eines _Images_ und enthält einen Befehl oder eine Datei, die dem _Image_ hinzugefügt wurde. Anhand der _Layer_ kann die ganze Historie des _Images_ nachvollzogen werden.\n\n**Quelle**\n[Wikipedia: Docker](https://de.wikipedia.org/wiki/Docker_(Software))\n\n---\n\n### Dockerfile\nEine Textdatei, die mit verschiedenen Befehlen ein _Image_ beschreibt. Diese werden bei der Ausführung abgearbeitet und für jeden Befehl ein einzelner _Layer_ angelegt.\n\n**Quelle**\n[Wikipedia: Docker](https://de.wikipedia.org/wiki/Docker_(Software))\n\n---\n\n# Fragen?\n\nAls nächstes: **docker-compose**\n\n---\n\n# docker-compose\n_docker-compose_ ist ein Werkzeug zur Definition und Ausführung von Multi-Container-Docker-Anwendungen. _docker-compose_ verwendet eine YAML-Datei, um die Dienste der Anwendung zu konfigurieren. Mit einem einzigen Befehl können anschließend alle Anwendungen gebaut und gestartet werden.\n\n**Quelle**\n[https://docs.docker.com/](https://docs.docker.com/compose/)\n\n---\n\n# docker-compose\n\nDie Verwendung von _docker-compose_ ist ein dreistufiger Prozess:\n\n 1. **Optional**: Definierung der Anwendung in einem _Dockerfile_\n 2. Definition der sogenannten _Services_ (aus denen die Applikation besteht) in der Datei `docker-compose.yml`\n 3. `docker-compose up` baut (sofern nötig) und startet alle definierten _Services_\n\n**Quelle**\n[https://docs.docker.com/](https://docs.docker.com/compose/)\n\n---\n\n## Minimaler Aufbau\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    image: php\n```\n\n---\n\n# Image - Aufbau\n\nSyntax: `image: \u003cwhat\u003e[:\u003cversion\u003e][-\u003chow\u003e][-\u003ckind\u003e]`\n\n---\n\n# Image - Version\n\n- `image: php:latest` (gleichbedeutend mit `image: php` - `:latest` ist implizit)\n- `image: php:8`\n- `image: php:8.0`\n- `image: php:7.1.33`\n\n---\n\n# Image - How \u0026 Kind (Tags)\n\n- `image: php:7.1-fpm` (`\u003chow\u003e` ist hier `fpm`. Alternative wäre z.B. `apache` oder `cli`)\n- `image: php:7.1-fpm-alpine` (`\u003ckind\u003e` ist `alpine`, ein **minimales** OS image. Alternative wären `buster` und `stretch`)\n\n---\n\n# Image - Other\n\n- `image: ubuntu`\n- `image: ubuntu:latest`\n- `image: ubuntu:20.04`\n- `image: GithubUser/php-custom`\n\n---\n\n# Container - Name\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    image: php:8.1\n```\n\nFormat: `\u003cfolder-name\u003e_\u003cservice-name\u003e_\u003cservice-index\u003e`\nAngenommen, dass `docker-compose.yml` im Ordner \"test\" liegt: `test_php_1`\n\n---\n\n# Container - Name\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    container_name: php\n    image: php:8.1\n```\n\n---\n\n# Ports\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    container_name: php\n    image: php:8.1\n  ports:\n    - \"8080:80\"\n```\n\n---\n\n# Ports\n\n## Short Syntax\n\n - Beide Ports angeben: `\u003cHost\u003e:\u003cContainer\u003e`\n - Nur den Container Port angeben (ein freier Ports auf dem Host wird zufällig ausgewählt): `:\u003cContainer\u003e`\n - Host-IP-Adresse und die Ports (default IP ist `0.0.0.0`): `\u003cip\u003e:\u003cHost\u003e:\u003cContainer\u003e`.\n\n---\n# Ports\n\n**WICHTIG**: Ports immer als String angeben\n\n\u003e When mapping ports in the HOST:CONTAINER format, you may experience erroneous results when using a container port lower than 60, because YAML parses numbers in the format xx:yy as a base-60 value. For this reason, we recommend always explicitly specifying your port mappings as strings.\n\n**Quelle**: [https://docs.docker.com/](https://docs.docker.com/compose/compose-file/compose-file-v3/#ports)\n\n---\n\n# Ports\n\n## Short Syntax - Beispiele\n\n```yml\nports:\n  - \"3000\"\n  - \"3000-3005\"\n  - \"8000:8000\"\n  - \"9090-9091:8080-8081\"\n  - \"49100:22\"\n  - \"127.0.0.1:8001:8001\"\n  - \"127.0.0.1:5000-5010:5000-5010\"\n  - \"127.0.0.1::5000\n  - \"6060:6060/udp\"\n  - \"12400-12500:1240\"\n```\n\n---\n\n# Ports\n\n## Long Syntax\n\n - `target`: Container Port\n - `published`: Host Port\n - `protocol`: Port Protokoll (`tcp` oder `udp`)\n - `mode`: _host_ für einen Host-Port oder _ingress_ für einen Port im Schwarmmodus für's Load-Balancing\n\n```yml\nports:\n  - target: 80\n    published: 8080\n    protocol: tcp\n    mode: host\n```\n\n---\n\n# Dependency\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    container_name: php\n    image: php:8.0-fpm-alpine\n    depends_on:\n      - db\n      - redis\n  redis:\n    image: redis\n  db:\n    image: postgres\n```\n\n---\n\n# Dependency\n\n - `docker-compose up` startet die definierten Services in der Reihenfolge der Abhängigkeiten. Im Beispiel: `db` \u003e `redis` \u003e `php`\n - `docker-compose up \u003cservice\u003e` schließt automatisch die Abhängigkeiten von `\u003cservice\u003e` ein. Daher **startet** `docker-compose up php` auch `db` und `redis`.\n - `docker-compose stop` **stoppt** Services in der Reihenfolge der Abhängigkeiten. Daher wird `php` vor `db` und `redis` gestoppt.\n\n**Quelle**\n[https://docs.docker.com/](https://docs.docker.com/compose/)\n\n---\n\n# Restart\n\n - `restart: \"no\"`: Default. Container wird unter keinen Umständen neugestartet\n - `restart: always`: Wann immer der Container beendet wird (z.B. durch einen Fehler oder weil eine Verbindung abbricht)\n - `restart: on-failure`: Nur wenn der Container durch einen Fehler beendet wurde\n - `restart: unless-stopped`: Solange bis der Container erfolgreich beendet wird (z.B. manuell)\n\n**Quelle**\n[https://docs.docker.com/](https://docs.docker.com/compose/)\n\n---\n\n# Restart - Beispiel\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    container_name: php\n    image: php:8.0-fpm-alpine\n  db:\n    image: postgres\n    restart: always\n```\n\n---\n\n# Volumes\n\nJeder Container geht bei jedem Start von der Image-Definition aus. Container können Dateien erstellen, aktualisieren und löschen, allerdings gehen diese Änderungen verloren, wenn der Container entfernt wird. Um das zu verhindern, benötigen wir _Volumes_.\n\nVolumes bieten die Möglichkeit, bestimmte Dateisystempfade des Containers mit dem Host-Rechner zu verbinden. Wenn ein Verzeichnis im Container _gemountet_ wird, werden Änderungen in diesem Verzeichnis auch auf dem Host-Rechner gesynct.\n\n**Quelle**\n[https://docs.docker.com/](https://docs.docker.com/compose/)\n\n---\n\n# Volumes\n\nSyntax:\n```yml\n  volumes:\n    - \u003chost\u003e:\u003ccontainer\u003e\n```\n\n---\n\n# Volumes - Beispiel\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    container_name: php\n    image: php:8.0-fpm-alpine\n    volumes:\n      - .:/var/www/html/\n```\n\n---\n\n# Volumes: Options\n\n```yml\nvolumes:\n  - .:/var/www/html/[:\u003coption\u003e]\n```\n\n---\n\n# Volumes: Options - consistent\n\n - `consistent` (_default_): Wenn sowohl Container als auch Host aktiv und kontinuierlich Änderungen an Daten vornehmen und es sowohl auf dem Host als auch im Container zeitgleich sichtbar sein soll.\n\nQuelle: [Docker Volumes](http://docs.docker.oeynet.com/engine/admin/volumes/bind-mounts/)\n\n---\n\n# Volumes: Options - cached\n\n - `cached`: Wenn der Host Änderungen durchführt, befindet sich der Container im _Readyonly_-Modus. Es kann zu Verzögerungen kommen, bevor Aktualisierungen, die auf dem Host vorgenommen werden, innerhalb des Containers sichtbar sind. **Verwenden wenn**: der Host ständig Daten ändert, die der Container liest und verwendet.\n\n```yml\nvolumes:\n  - config/:/etc/var/www:cached\n```\n\nQuelle: [Docker Volumes](http://docs.docker.oeynet.com/engine/admin/volumes/bind-mounts/)\n\n---\n\n# Volumes: Options - delegated\n\n - `delegated`: Wenn der Docker-Container Änderungen durchführt, ist der Host im _Readyonly_-Modus. Es kann zu Verzögerungen kommen, bevor Aktualisierungen, die in einem Container vorgenommen werden, auf dem Host sichtbar sind.\n\n\n```yml\nvolumes:\n  - config/:/etc/var/www:delegated\n```\n\nQuelle: [Docker Volumes](http://docs.docker.oeynet.com/engine/admin/volumes/bind-mounts/)\n\n---\n\n# Volumes: Warum `delegated`?\n\n\u003eMac uses osxfs to propagate directories and files shared from macOS to the Linux VM. This propagation makes these directories and files available to Docker containers running on Docker Desktop for Mac. **By default, these shares are fully-consistent, meaning that every time a write happens on the macOS host or through a mount in a container, the changes are flushed to disk so that all participants in the share have a fully-consistent view.\n\n\u003eFull consistency can severely impact performance in some cases.** Docker 17.05 and higher introduce options to tune the consistency setting on a per-mount, per-container basis.\n\nQuelle: [Docker Volumes](http://docs.docker.oeynet.com/engine/admin/volumes/bind-mounts/)\n\n---\n\n# Volumes: Options - Read-Only\n\n - `ro`: Der Ordner / die Datei ist im Container nur lesend einsehbar\n\n```yml\nvolumes:\n  - .docker/config/php.ini:/etc/php/php.ini:ro\n```\n\nQuelle: [Docker Volumes](http://docs.docker.oeynet.com/engine/admin/volumes/bind-mounts/)\n\n---\n\n# Networks\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    container_name: php\n    image: php:8.0-fpm-alpine\n    volumes:\n      - .:/var/www/html/\n    networks:\n      - backend\n\nnetworks:\n  backend:\n    name: backend\n    driver: bridge\n```\n---\n\n# Networks - Wozu?\n\n - Services im selben `docker-compose.yml` sind implizit über dasselbe, interne Netzwerk verbunden (_default_)\n - Services aus anderen `docker-compose.yml` sind es nicht. Diese können aber, wenn sie im selben Netzwerk (= gleicher Name) sind, miteinander über dieses Netzwerk kommunizieren\n\n---\n\n# Networks - Driver\n\n - `bridge`: Default. Wird verwendet, wenn die verschiedenen Anwendungen in eigenständigen Containern laufen, die miteinander kommunizieren müssen.\n - `host`: Für eigenständige Containern. Die Netzwerkisolierung zwischen dem Container und dem Docker-Host wird aufgehoben. Stattdessen wird direkt das Netzwerk des Hosts verwendet.\n - `overlay`: I.d.R. nur für `docker-swarm` relevant\n - `macvlan`: Ermöglicht einem Container eine MAC-Adresse zuzuweisen, sodass dieser wie ein physisches Gerät im Netzwerk erscheint. Der Datenverkehr wird durch diese MAC-Adresse an die Container weitergeleitet.\n - `none`: Networks sind deaktiviert. (Achtung bei `docker-swarm`)\n\nQuelle: [Docker Networks](https://docs.docker.com/compose/networking/)\n\n---\n\n# Networks - external\n\n```yml\nnetworks:\n  frontend:\n    name: frontend\n    external: true\n```\n\n**vs**\n\n```yml\nnetworks:\n  frontend:\n    name: frontend\n    driver: bridge\n```\n\n---\n\n# Fragen? Kurze Pause?\n\nAls nächstes: **Dockerfile**\n\n---\n\n# Dockerfile\n\nWir möchten die folgenden Pakete installieren:\n\n - `bash` zur Auto-Completion\n - `git` for obvious reasons\n - `shadow` um Benutzer zu verwalten (Docker startet alles als Root - BAD!)\n - `ssh` \u0026 `ssl`\n\n---\n\n# Dockerfile - docker-compose\n\n```yml\nversion: \"3.7\"\n\nservices:\n  php:\n    container_name: php\n    build:\n      dockerfile: ./.docker/php/Dockerfile\n      context: .\n      args:\n        USER_ID: $USER_ID\n    volumes:\n      - .:/var/www/html/\n```\n\n---\n\n## Context\n\nDurch den Verweis `dockerfile: ./.docker/php/Dockerfile` wird als _context_ `./.docker/php/` verwendet. Das heißt, dass das kopieren von Dateien von `./.docker/php/` ausgeht. Um einen anderen Ordner als Context zu verwenden, kann die Option `context \u003cfolder\u003e` benutzt werden. Um z.B. im derzeitigen Ordner zu bleiben, wird `context: .` definiert.\n\n---\n\n# Dockerfile\n\n```Dockerfile\nFROM php:8.0-fpm-alpine\n\nARG USER_ID=1000\n\nRUN apk update --quiet \u0026\u0026 \\\n    apk add --quiet --no-cache bash git shadow openssh openssl-dev\n\nWORKDIR .\nCOPY . .\n\nCOPY --chown=www-data:www-data --from=composer:2 /usr/bin/composer /usr/local/bin/composer\n\nRUN usermod -u $USER_ID www-data \u0026\u0026 chown -R www-data:www-data /var/www/ .\nUSER www-data\n\nCMD [\"php-fpm\"]\n```\n\n---\n\n## FROM\n\n**Syntax**: `FROM \u003cimage\u003e [AS \u003cname\u003e]`\n\n - `FROM php:8`\n - `FROM php:latest`\n - `FROM php:7.1`\n - `FROM php:8.0-fpm`\n - `FROM php:8.0-fpm-alpine`\n\n---\n\n## ARG\n\n**Syntax**: `ARG \u003cname\u003e[=\u003cdefault value\u003e]`\n\n - `ARG USER_ID`\n - `ARG USER_ID=1000`\n\n---\n\n## RUN\n\n**Syntax**: `RUN \u003ccommand\u003e`\n\n```Dockerfile\nRUN apk update --quiet \u0026\u0026 \\\n    apk add --quiet --no-cache bash git shadow openssh openssl-dev\n```\n\n---\n\n## WORKDIR\n\n**Syntax**: `WORKDIR \u003cfolder\u003e`\n\n`WORKDIR .`\n\n---\n\n## COPY\n\n**Syntax**: `COPY \u003csrc\u003e \u003cdest\u003e`\n\n`COPY . .`\n\n**WICHTIG**: Wenn `WORKDIR` spezifiziert ist, geht der Pfad im Container von diesem aus.\n\n---\n\n## COPY\n\nEs ist auch möglich, von anderen _images_ etwas zu kopieren.\n\n**Syntax**: `COPY [--chown=\u003cuser\u003e:\u003cgroup\u003e] [--from=\u003cimage\u003e] \u003csrc\u003e \u003cdest\u003e`\n\n`COPY --chown=www-data:www-data --from=composer:2 /usr/bin/composer /usr/local/bin/composer`\n\n---\n\n## USER\n\n**Syntax**: `USER \u003cuser-on-os\u003e`\n\n`USER www-data`\n\n---\n\n## CMD\n\n**Syntax**: `CMD [\u003ccmd\u003e, \u003carg1\u003e, \u003carg2\u003e, ...]`\n\n**Achtung**: `[` ist hier **kein** Anzeichen für ein optionales Argument\n\n - `CMD [\"php-fpm\"]`\n - `CMD [\"php\", \"-S\", \"0.0.0.0:9000\"]`\n\n**WICHTIG**: Bei letzterem ist der _Port_ **im** Container. Um diesen Port vom Host aus anzusprechen, muss im _docker-compose.yml_ ein entsprechendes Port-Mapping stattfinden.\n\n---\n\n# Good to know\n\n---\n\n## ENV\n\n`ENV` kann verwendet werden, um die Umgebungsvariable _PATH_ zu aktualisieren.\n\n**Syntax**: `ENV \u003cname\u003e=\u003cvalue\u003e`\n\n---\n\n## ENV - Beispiel\n\n```Dockerfile\nENV PG_MAJOR=9.3\nENV PG_VERSION=9.3.4\nRUN curl -SL https://example.com/postgres-${PG_VERSION}.tar.xz | tar -xJC /usr/src/postgres\nENV PATH=/usr/local/postgres-${PG_MAJOR}/bin:${PATH}\n```\n---\n\n# Fragen? Kurze Pause?\n\nAls nächstes: **Best practise** \u0026 **Multi-Staged**\n\n---\n\n# Best practise\n\nEine der größten Herausforderungen beim Erstellen von Images ist es, die Größe des Images gering zu halten. Jede Anweisung im Dockerfile fügt dem Image eine Schicht hinzu (die sogenannten _Layer_).\n\n---\n\n## Best practise - Nicht so gut\n\n```Dockerfile\nFROM golang:1.7.3\nWORKDIR /go/src/github.com/alexellis/href-counter/\nCOPY app.go .\nRUN go get -d -v golang.org/x/net/html\nRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .\n```\n\n---\n\n## Best practise - Nicht so gut\n\n```Dockerfile\nFROM golang:1.7.3\nWORKDIR /go/src/github.com/alexellis/href-counter/\nCOPY app.go .\nRUN go get -d -v golang.org/x/net/html\nRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .\n```\n\nZwei `RUN` - Zwei Layer\n\n---\n\n## Best practise - Besser\n\n```Dockerfile\nFROM golang:1.7.3\nWORKDIR /go/src/github.com/alexellis/href-counter/\nCOPY app.go .\nRUN go get -d -v golang.org/x/net/html \\\n    \u0026\u0026 CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .\n```\n\n**Quelle**: [https://docs.docker.com/](https://docs.docker.com/develop/develop-images/multistage-build/)\n\n---\n\n# Multi-Staged\n\n---\n\n## Multi-Staged - Nicht so gut\n\n```Dockerfile\nFROM golang:1.7.3\nWORKDIR /go/src/github.com/alexellis/href-counter/\nRUN go get -d -v golang.org/x/net/html\nCOPY app.go .\nCMD [\"./app\"]\n```\n\n---\n\n## Multi-Staged - Besser\n\n```Dockerfile\nFROM golang:1.7.3 AS builder\nWORKDIR /go/src/github.com/alexellis/href-counter/\nRUN go get -d -v golang.org/x/net/html\nCOPY app.go .\n\nFROM alpine:latest\nWORKDIR /root/\nCOPY --from=builder /go/src/github.com/alexellis/href-counter/app .\nCMD [\"./app\"]\n```\n\n**Quelle**: [https://docs.docker.com/](https://docs.docker.com/develop/develop-images/multistage-build/)\n\n---\n\n# Makefile\n\n`make` ist ein build Tool um komplexe Befehle (und ggf. deren Abhängigkeiten) zusammenzufassen. Ein _Makefile_ besteht aus sogenannten _Targets_, optional Abhängigkeiten (separiert durch mind. einem Leerzeichen) und ausführbare Befehle. Letztere werden per Tab eingerückt unterhalb der _Targets_ und deren optionalen Abhängigkeiten. Ein Beispiel:\n\n```Makefile\nA: C B\n\t@echo \"World\"\nB:\n\t@echo \"my\"\nC:\n\t@echo \"Hello\"\n```\n\nWas kommt bei der Ausführung von `make A` raus?\n\n---\n\n# Makefile\n\nDer Befehl `make A` würde im _Target_ `A` die Abhängigkeit zu `C` und `B` sehen und somit zunächst `C`, dann `B` und danach erst `A` ausführen. Die Ausgabe wäre:\n```\nHello\nmy\nWorld\n```\n\n---\n\n# Makefile: Benennung\n\nUm direkt per `make A` das _Target_ `A` auszuführen, muss die Datei `Makefile` heißen (so wie die Standard Datei für Docker `Dockerfile` heißt).\n\nWenn die Datei nicht `Makefile` heißt oder heißen soll/kann, dann muss die Datei auf die Endung `*.mk` enden und kann mit dem `-f` Argument eingelesen werden. Würde die Datei also z.B. `test.mk` heißen, würde das _Target_ `A` wie folgt ausgeführt werden: `make -f test.mk A`\n\n---\n\n# Makefile: Wozu?\n\nUm z.B. per _docker-compose_ einen neuen Container von Grund auf zu bauen und ältere Artefakte loszuwerden, muss man den folgenden Befehl ausführen:\n\n`docker-compose up -d --build --remove-orphans`\n\nDas ist lang und umständlich. Stattdessen kann ein _Makefile_  verwendet werden mit dem folgenden Inhalt:\n\n```Makefile\nbuild:\n\tdocker-compose up -d --build --remove-orphans\n```\n\nWas dann per `make build` ausgeführt werden kann.\n\n---\n\n# Makefile: Warum kein Shell-Script?\n\n - Shell Scripte sind nicht unbedingt kompatibel zwischen unterschiedlichen Shells (`sh`, `dash`, `bash`, `fish`, `zsh`, etc.)\n - Die Syntax ist komplexer\n - `make` ist auf jedem Linux-artigen Betriebssystem (und oft auch bei Windows) vorinstalliert\n\n---\n\n# Fragen? Kurze Pause?\n\nAls nächstes: **Localstack**\n\n---\n\n# Localstack\n\n![](localstack.png)\n\n---\n\n# Localstack\n\n\u003e LocalStack provides an easy-to-use test/mocking framework for developing Cloud applications. It spins up a testing environment **on your local machine** that provides the same functionality and APIs as the real AWS cloud environment.\n[...]\nYour application is developed entirely on the local developer machines. LocalStack provisions all required \"cloud\" resources in a local container.\n[...]\nOnce all tests are green, you flip the switch and the application can be seamlessly deployed to the real AWS cloud environment.\n\n[Quelle](https://localstack.cloud/)\n\n---\n\n# Localstack\n\n```yml\nversion: \"3.7\"\n\nservices:\n  localstack:\n    container_name: localstack_main\n    image: localstack/localstack:latest\n    ports:\n      - \"4566:4566\"\n    environment:\n      - DEBUG=1\n      - DATA_DIR=.localstack/data\n      - SERVICES=es,firehose\n    volumes:\n      - \".localstack:/tmp/localstack\"\n      - \"/var/run/docker.sock:/var/run/docker.sock\"\n```\n\n---\n\n# Localstack\n\n - `DEBUG` ⇒ `int` (1 ⇒ true, 0 ⇒ false)\n  Um Fehler beim starten von Localstack oder deren Services besser zu identifizieren\n - `DATA_DIR` ⇒ `string`\n  Lokales Verzeichnis zum Speichern persistenter Daten\n - `SERVICES` ⇒ `string`\n  Komma-separierte Liste der AWS-Services, die gestartet werden sollen. Die Servicenamen entsprechen im Wesentlichen den Servicenamen der `aws-cli` (`kinesis`, `lambda`, `sqs`, `es`, etc.)\n\nQuelle: [localstack](https://github.com/localstack/localstack)\n\n---\n\n# aws-cli installieren\n\n\u003e$ aws --version\n\n\u003eaws-cli/2...\n\n---\n\n# aws-cli installieren: Linux / WSL\n\n - `curl \"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip\" -o \"awscliv2.zip\"`\n - `unzip awscliv2.zip`\n - `sudo ./aws/install`\n\n---\n\n# aws-cli installieren: Windows\n\n - https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-windows.html\n\n---\n\n# aws-cli installieren: Mac\n\n - https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html\n\n---\n\n# aws-cli ausführen\n\n## Service ausführen:\n\u003e aws \u003cservice\u003e \u003caction\u003e [options]\n\n## Lokale Ausführung:\n\u003e aws **--endpoint-url=http://localhost:4566** \u003cservice\u003e \u003caction\u003e [options]\n\n---\n\n# Localstack - Beispiel\n\n[![](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcbiAgQVtFeHRlcm5lIFN5c3RlbWVdLS0-fElucHV0fCBCW0FQSV1cbiAgQi0uLT5DMShGaXJlaG9zZSBTdHJlYW1zKSAmIEMyKEZpcmVob3NlIFN0cmVhbXMpICYgQzMoRmlyZWhvc2UgU3RyZWFtcylcbiAgQzEtLi0-RChFbGFzdGljc2VhcmNoIFNlcnZpY2UpXG4gIEMyLS4tPkRcbiAgQzMtLi0-RFxuXHRcdCIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2UsImF1dG9TeW5jIjp0cnVlLCJ1cGRhdGVEaWFncmFtIjpmYWxzZX0)](https://mermaid-js.github.io/mermaid-live-editor/edit##eyJjb2RlIjoiZ3JhcGggTFJcbiAgQVtFeHRlcm5lIFN5c3RlbWVdLS0-fElucHV0fCBCW0FQSV1cbiAgQi0uLT5DMShGaXJlaG9zZSBTdHJlYW1zKSAmIEMyKEZpcmVob3NlIFN0cmVhbXMpICYgQzMoRmlyZWhvc2UgU3RyZWFtcylcbiAgQzEtLi0-RChFbGFzdGljc2VhcmNoIFNlcnZpY2UpXG4gIEMyLS4tPkRcbiAgQzMtLi0-RFxuXHRcdCIsIm1lcm1haWQiOiJ7XG4gIFwidGhlbWVcIjogXCJkZWZhdWx0XCJcbn0iLCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6ZmFsc2V9)\n\n---\n\n# Localstack - Beispiel\n\n```sh\ndocker-compose -f localstack/docker-compose.yml up -d\n```\n\n---\n\n# Localstack - Elasticsearch Service\n\n\u003e aws --endpoint-url=http://localhost:4566 es create-elasticsearch-domain --domain-name es_local\n\n - Service: `es`\n - Action: `create-elasticsearch-domain`\n - Options:\n    - `--domain-name` ⇒ `es_local`\n\n---\n\n# Localstack - Elasticsearch Service\n\n## Relevant für Production:\n - `--elasticsearch-version \u003cvalue\u003e`\n - `--elasticsearch-cluster-config \u003cvalue\u003e`\n\n[aws-cli Dokumentation](https://docs.aws.amazon.com/cli/latest/reference/es/create-elasticsearch-domain.html)\n\n---\n\n# Localstack - Elasticsearch Service\n\n - 7.10, 7.9, 7.8, 7.7, 7.4, 7.1\n - 6.8, 6.7, 6.5, 6.4, 6.3, 6.2, 6.0\n - 5.6, 5.5, 5.3, 5.1\n - 2.3\n - 1.5\n\n[Dokumentation](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/what-is-amazon-elasticsearch-service.html#aes-choosing-version)\n\n---\n\n# Localstack - Elasticsearch Service\n\n - `InstanceType` ⇒ `m3.medium.elasticsearch`\n - `InstanceCount`\n - `DedicatedMasterEnabled`\n - `DedicatedMasterType` ⇒ `m3.large.elasticsearch`\n - `DedicatedMasterCount`\n\n---\n\n# Localstack - Elasticsearch Service\n\n - **Relevant** für Production \u0026#8660; **Irrelevant** für local(stack)\n\n---\n\n# Localstack - Elasticsearch Service\n\n - **Relevant** für Production \u0026#8660; **Irrelevant** für local(stack)\n    - In `localstack` wird Elasticsearch Service durch ein **internes** Elasticsearch Cluster mit **einem Node** abgebildet\n  ⇒ [Localstack - Externe Services](#localstack---externe-services)\n\n---\n\n# ARN\n\n**A**mazon **R**esource **N**ames\n\n## Format\n\n- `arn:partition:service:region:account-id:resource-id`\n- `arn:partition:service:region:account-id:resource-type/resource-id`\n- `arn:partition:service:region:account-id:resource-type:resource-id`\n\n[Dokumentation](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)\n\n---\n\n# aws-cli: ARN\n\n - Response der `create-elasticsearch-domain` Action\n - `aws es describe-elasticsearch-domain --domain-name es_local`\n\n**Output**:\n```json\n{\n  ...\n  \"ARN\": arn:aws:es:us-east-1:000000000000:domain/es_local,\n  ...\n}\n```\n\n---\n\n# Fragen? Kurze Pause?\n\nAls nächstes: **Localstack - Firehose**\n\n---\n\n# Localstack - Firehose\n\n[![](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcbiAgQVtFeHRlcm5lIFN5c3RlbWVdLS0-fElucHV0fCBCW0FQSV1cbiAgQi0uLT5DMShGaXJlaG9zZSBTdHJlYW1zKSAmIEMyKEZpcmVob3NlIFN0cmVhbXMpICYgQzMoRmlyZWhvc2UgU3RyZWFtcylcbiAgQzEtLi0-RChFbGFzdGljc2VhcmNoIFNlcnZpY2UpXG4gIEMyLS4tPkRcbiAgQzMtLi0-RFxuICBzdHlsZSBEIGZpbGw6I2Y5Zixjb2xvcjojZmZmO1xuICBzdHlsZSBDMSBmaWxsOiNmOTYsY29sb3I6I2ZmZjtcbiAgc3R5bGUgQzIgZmlsbDojZjk2LGNvbG9yOiNmZmY7XG5cdHN0eWxlIEMzIGZpbGw6I2Y5Nixjb2xvcjojZmZmO1xuICBsaW5rU3R5bGUgNCBzdHJva2U6I2Y5NlxuICBsaW5rU3R5bGUgNSBzdHJva2U6I2Y5NlxuICBsaW5rU3R5bGUgNiBzdHJva2U6I2Y5NiIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2UsImF1dG9TeW5jIjp0cnVlLCJ1cGRhdGVEaWFncmFtIjpmYWxzZX0)](https://mermaid-js.github.io/mermaid-live-editor/edit/##eyJjb2RlIjoiZ3JhcGggVERcbiAgQVtFeHRlcm5lIFN5c3RlbWVdLS0-fElucHV0fCBCW0FQSV1cbiAgQi0uLT5DMShGaXJlaG9zZSBTdHJlYW1zKSAmIEMyKEZpcmVob3NlIFN0cmVhbXMpICYgQzMoRmlyZWhvc2UgU3RyZWFtcylcbiAgQzEtLi0-RChFbGFzdGljc2VhcmNoIFNlcnZpY2UpXG4gIEMyLS4tPkRcbiAgQzMtLi0-RFxuICBzdHlsZSBEIGZpbGw6I2Y5ZjtcbiAgc3R5bGUgQzEgZmlsbDojZjk2LGNvbG9yOiNmZmY7XG4gIHN0eWxlIEMyIGZpbGw6I2Y5Nixjb2xvcjojZmZmO1xuXHRzdHlsZSBDMyBmaWxsOiNmOTYsY29sb3I6I2ZmZjtcbiAgbGlua1N0eWxlIDQgc3Ryb2tlOiNmOTZcbiAgbGlua1N0eWxlIDUgc3Ryb2tlOiNmOTZcbiAgbGlua1N0eWxlIDYgc3Ryb2tlOiNmOTYiLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ)\n\n---\n\n# Localstack - Firehose: Create Stream\n\n\u003e aws --endpoint-url=http://localhost:4566 **firehose** ...\n\n - Service: `firehose`\n\n---\n\n# Localstack - Firehose: Create Stream\n\n\u003e aws --endpoint-url=http://localhost:4566 firehose **create-delivery-stream** ...\n\n - Service: `firehose`\n - Action: `create-delivery-stream`\n\n---\n\n# Localstack - Firehose: Create Stream\n\n\u003e aws --endpoint-url=http://localhost:4566 firehose create-delivery-stream **--delivery-stream-name firehose_es_local_stream** ...\n\n - Service: `firehose`\n - Action: `create-delivery-stream`\n - Options:\n    - `--delivery-stream-name` ⇒ `firehose_es_local_stream`\n\n---\n\n# Localstack - Firehose: Create Stream\n\n\u003e aws --endpoint-url=http://localhost:4566 firehose create-delivery-stream --delivery-stream-name firehose_es_local_stream **--delivery-stream-type DirectPut** ...\n\n - Service: `firehose`\n - Action: `create-delivery-stream`\n - Options:\n    - `--delivery-stream-name` ⇒ `firehose_es_local_stream`\n    - `--delivery-stream-type` ⇒ `DirectPut`\n\n---\n\n# Localstack - Firehose: Create Stream\n\n\u003e aws --endpoint-url=http://localhost:4566 firehose create-delivery-stream --delivery-stream-name firehose_es_local_stream --delivery-stream-type DirectPut **--elasticsearch-destination-configuration \"RoleARN=arn:aws:iam::000000000000:role/Firehose-Reader-Role,DomainARN=_\u003cARN\u003e_,IndexName=test,ProcessingConfiguration={Enabled=false}\"**\n\n---\n\n# Localstack - Firehose: Create Stream\n\n - `RoleARN` ⇒ `arn:aws:iam::000000000000:role/Firehose-Reader-Role`\n - `DomainARN` ⇒ z.B. für localstack `arn:aws:es:us-east-1:000000000000:domain/es_local`\n    - Alternativ: `ClusterEndpoint` mit der **Host**-URL (mit Port)\n - `IndexName` ⇒ `test`\n - `ProcessingConfiguration`:\n    - `Enabled` ⇒ `false`\n\n---\n\n# Localstack - Firehose: Put-Record\n\n---\n\n# Localstack - Firehose: Put-Record\n\n\u003e aws --endpoint-url=http://localhost:4566 **firehose** ...\n\n - Service: `firehose`\n\n---\n\n# Localstack - Firehose: Put-Record\n\n\u003e aws --endpoint-url=http://localhost:4566 firehose **put-record** ...\n\n - Service: `firehose`\n - Action: `put-record`\n\n---\n\n# Localstack - Firehose: Put-Record\n\n\u003e aws --endpoint-url=http://localhost:4566 firehose put-record **--delivery-stream-name firehose_es_local_stream** ...\n\n - Service: `firehose`\n - Action: `put-record`\n - Options:\n    - `--delivery-stream-name` ⇒ `firehose_es_local_stream`\n\n---\n\n# Localstack - Firehose: Put-Record\n\n\u003e aws --endpoint-url=http://localhost:4566 firehose put-record --delivery-stream-name firehose_es_local_stream **--record '{\"Data\":\"eyAidGFyZ2V0IjogImJlcnJ5IiB9\"}**'\n\n - Service: `firehose`\n - Action: `put-record`\n - Options:\n    - `--delivery-stream-name` ⇒ `firehose_es_local_stream`\n    - `--record` ⇒ `{\"Data\":\"eyAidGFyZ2V0IjogImJlcnJ5IiB9\"}`\n---\n\n# Localstack - Firehose: Put-Record\n\n```json\n{ \"Data\": Blob }\n```\n\n**Blob**: `eyAidGFyZ2V0IjogImJlcnJ5IiB9`\n\n```json\n{ \"target\": \"berry\" }\n```\n\n_base64_ encoded\n\n---\n\n# Fragen? Kurze Pause?\n\nAls nächstes: **Localstack - Externe Services**\nDanach: **Ende**\n\n---\n\n# Localstack - Externe Services\n\n---\n\n# Localstack - Externe Services\n\n - `\u003cSERVICE\u003e_BACKEND`\n - `\u003cSERVICE\u003e_PORT`\n\n---\n\n# Localstack - Externe Services\n\n`\u003cSERVICE\u003e` kann für einen der folgenden Services stehen:\n\n - `APIGATEWAY`\n - `CLOUDFORMATION`\n - `DYNAMODB`\n - `ELASTICSEARCH`\n - `KINESIS`\n - `S3`\n - `SNS`\n - `SQS`\n\n---\n\n# Localstack - Externe Services\n\n- `Elasticsearch`: Docker\n- `DynamoDB`\n  - https://github.com/mhart/dynalite\n  - https://hub.docker.com/r/amazon/dynamodb-local/\n- `Kinesis`\n  - https://github.com/mhart/kinesalite\n- `SQS`\n  - https://github.com/softwaremill/elasticmq\n\n---\n\n# Localstack - Externe Services: Elasticsearch\n\n - `ELASTICSEARCH_BACKEND`\n - `ELASTICSEARCH_PORT`\n\n ⇒ **innerhalb von Docker**\n\n---\n\n# Localstack - Externe Services: Elasticsearch\n\n```yml\nversion: \"3.7\"\n\nservices:\n  localstack:\n    container_name: localstack_main\n    image: localstack/localstack:latest\n    ports:\n      - \"4566:4566\"\n    environment:\n      - DEBUG=1\n      - DATA_DIR=.localstack/data\n      - SERVICES=es,firehose\n      - ELASTICSEARCH_BACKEND=http://es_in_docker\n      - ELASTICSEARCH_PORT=9200\n    volumes:\n      - \".localstack:/tmp/localstack\"\n      - \"/var/run/docker.sock:/var/run/docker.sock\"\n```\n\n---\n\n# Localstack - Externe Services: Elasticsearch\n\n\u003e aws --endpoint-url=http://localhost:4566 es create-elasticsearch-domain --domain-name es_local\n\n ⇒ **immer noch nötig**, damit localstack sich mit dem externen Service verbindet!\n\n---\n\n# That's it Folks\n## Fragen?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdgame%2Fdocker-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdgame%2Fdocker-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdgame%2Fdocker-tutorial/lists"}