Skip to content

Commit b630a1d

Browse files
committed
Lab-Beschreibungen und Slides
1 parent 68586a0 commit b630a1d

File tree

13 files changed

+1094
-0
lines changed

13 files changed

+1094
-0
lines changed

Lab1/Tasks.md

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Lab 1 - Pulumi Grundlagen
2+
3+
## Überblick
4+
5+
In der ersten Übung werden wir uns mit den Grundlagen von Pulumi vertraut machen. Hierzu gehört
6+
7+
- der Umgang mit der Pulumi CLI,
8+
- das Erstellen eines Projekts und Stacks,
9+
- das Hinzufügen von Konfiguration und Secrets
10+
- und das Exportieren eines Outputs.
11+
12+
## Pulumi CLI
13+
14+
### Login
15+
16+
Jeder sollte vor Teilnahme bereits ein Pulumi Konto erzeugt haben (falls nicht, nun hier schnell nachholen: <https://app.pulumi.com/> und am Einfachsten direkt Euren GitHub Login verwenden).
17+
18+
```bash
19+
pulumi login
20+
```
21+
22+
Es gibt die Möglichkeit, sich interaktiv via Browser anzumelden oder ein AccessToken in der Pulumi Konsole zu generieren und dieses für den Login auf der Kommandozeile zu verwenden.
23+
Eine nicht-interaktive Anmeldung wird ebenfalls unterstützt, in dem ein AccessToken über die Environment-Variable `PULUMI_ACCESS_TOKEN` angegeben wird. Ich selbst verwende im Workshop ein AccessToken.
24+
25+
```bash
26+
pulumi whoami # zeigt den derzeit angemeldeten User an
27+
```
28+
29+
### Erstes Projekt
30+
31+
Wir erzeugen nun unser erstes Pulumi Projekt mit unserem ersten Stack. Dazu führen wir folgenden Befehl aus:
32+
33+
```bash
34+
pulumi new
35+
```
36+
37+
Wir wählen `typescript` als Template für das Projekt, und belassen die weiteren Einstellungen wie sie sind. Als Ergebnis erhalten wir einen neuen Pulumi Stack `lab1/dev`.
38+
Dies lässt sich leicht überprüfen, in dem wir die Stacks auflisten:
39+
40+
```bash
41+
pulumi stack ls
42+
```
43+
44+
:bulb: Nehmt Euch kurz Zeit und schaut Euch die Dateien im erzeugten Pulumi Projekt an.
45+
46+
:mag: Das erzeugte Projekt ist letztlich ein ganz normales **Typescript** Projekt mit vielen Bekannten: `.gitignore, tsconfig.json, package.json, index.ts, ...` Die einzige zusätzliche Datei ist `Pulumi.yaml`, diese enthält Informationen zum aktuellen Projekt:
47+
48+
```yaml
49+
name: lab1
50+
runtime: nodejs
51+
description: A minimal TypeScript Pulumi program
52+
```
53+
54+
---
55+
56+
Nun erzeugen wir zwei weitere Stacks:
57+
58+
```bash
59+
pulumi stack init staging # erzeugt Stack lab1/staging
60+
pulumi stack init prod # erzeugt Stack lab1/prod
61+
```
62+
63+
Wir wechseln zwischen den Stacks:
64+
65+
```bash
66+
pulumi stack select dev
67+
pulumi stack select staging
68+
pulumi stack select prod
69+
pulumi stack select dev
70+
```
71+
72+
:mag: Obwohl wir mehrere Stacks erzeugt haben, hat sich keine Datei verändert bzw. ist eine neue Datei im Projekt hinzugekommen. Dies liegt daran, dass die Information über die Stacks selbst vom Pulumi Service verwaltet werden.
73+
74+
:bulb: Ähnlich wie bei Terraform gibt es die Möglichkeit, das State-Management ohne den Pulumi-Service zu betreiben (und den State z.B. auf AWS S3 oder Azure BlobStorage abzulegen). Es gibt hierzu nicht wirklich viel Information im Netz, ein guter Ansatz wird von Sam Cogan [hier](https://samcogan.com/storing-pulumi-state-in-azure/) in seinem Blogpost beschrieben.
75+
76+
### Konfiguration eines Stacks
77+
78+
Es können unabhängig für jeden Stack Konfigurationsparameter und Secrets verwaltet werden. Das ist insofern interessant, als dass man damit für unterschiedliche Umgebungen andere Parametersätze verwenden kann. In einer DEV Umgebung reichen vielleicht weniger und kleinere VMs, als in einer PROD Umgebung. Stacks kann man also als Strukturelement verwenden, um verschiedene Environments zu modellieren.
79+
80+
#### Konfiguration
81+
82+
Im ersten Schritt legen wir einen Config-Parameter im Stack `lab1/dev` an:
83+
84+
```bash
85+
pulumi stack select dev
86+
pulumi config set myname Florian-dev
87+
```
88+
89+
:bulb: Durch das Festlegen eines Config-Parameters ist im Projektverzeichnis eine neu Datei entstanden.
90+
91+
:muscle: **Lege für die anderen Stacks ebenfalls einen solchen Config-Parameter an!**
92+
93+
#### Secrets
94+
95+
Im zweiten Schritt legen wir nun ein Secret im Stack `lab1/dev` an:
96+
97+
```bash
98+
pulumi stack select dev
99+
pulumi config set mysecret secret-dev --secret
100+
```
101+
102+
:bulb: Das erstellte Secret wird verschlüsselt in der Stack-Konfigurationsdatei gespeichert (hier `Pulumi.dev.yaml`).
103+
104+
:muscle: **Lege für die anderen Stacks ebenfalls ein solches Secret an!**
105+
106+
### Nutzung der Konfiguration im Pulumi Programm
107+
108+
Wir schreiben nun zum ersten Mal Code für unser Pulumi Programm, und zwar in die `index.ts`:
109+
110+
```ts
111+
import * as pulumi from "@pulumi/pulumi";
112+
113+
const config = new pulumi.Config();
114+
115+
const myname = config.require("myname");
116+
const mysecret = config.requireSecret("mysecret");
117+
118+
const optionalConfigParameter = config.get("optional") || "defaultValue";
119+
120+
export const name = myname;
121+
export const secret = mysecret;
122+
```
123+
124+
Im Terminal führen wir nun den wohl wichtigsten Pulumi Befehl aus:
125+
126+
```bash
127+
pulumi up # 'pulumi up -y' um ohne Nachfrage auszuführen
128+
```
129+
130+
Dieser Aufruf veranlasst Pulumi unser Programm auszuführen, den
131+
**desired state**
132+
daraus abzuleiten und anschließend dafür zu sorgen, dass
133+
**desired state == actual state**
134+
135+
Nach Beendigung des Befehls sehen wir, dass Pulumi zwei Outputs erzeugt hat:
136+
137+
```bash
138+
name : "Florian"
139+
secret: "[secret]"
140+
```
141+
142+
Diese können wir uns auch gezielt anzeigen lassen:
143+
144+
```bash
145+
pulumi stack output
146+
```
147+
148+
Um die Secrets in Plaintext sehen zu können:
149+
150+
```bash
151+
pulumi stack output --show-secrets
152+
```
153+
154+
:muscle: **Weitere Aufgaben**
155+
156+
1. Führe `pulumi up` auch für die anderen Stacks durch.
157+
2. Füge den optionalen Parameter in einem Stack hinzu.
158+
3. Entferne einen der benötigten Parameter aus einem Stack und provoziere damit einen Fehler.

Lab10/Tasks.md

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Lab 10 - Kubernetes Deployment & Service
2+
3+
## Überblick
4+
5+
In dieser Übung werden wir ein Kubernetes Deployment und einen Service erstellen und damit den Pod ablösen, den wir in einer vorherigen Übung erstellt haben.
6+
7+
### Neues Projekt erstellen
8+
9+
1. Ein neues Pulumi Projekt mit Namen `lab10` erstellen: `pulumi new kubernetes-typescript`
10+
11+
### Pulumi & Kubernetes YAML
12+
13+
Die Nutzung von Kubernets Resourcen in Pulumi unterscheidet sich eigentlich nur in der verwendeten Sprache vom 'herkömmlichen' Definieren von Kubernets Resourcen in YAML. Es gibt auch ein Tool names [kube2pulumi](https://www.pulumi.com/kube2pulumi/), mit dem vorhandenes YAML in ein Pulumi Programm übersetzt werden kann.
14+
15+
### Aufgaben
16+
17+
1. KubeConfig aus Lab7 benutzen und KubernetesProvider erstellen.
18+
2. Kubernetes Namespace `lab10` erstellen.
19+
3. Deployment und Service erstellen. Siehe nachfolgendes Codegerüst.
20+
21+
```ts
22+
const appLabels = {
23+
// key: value
24+
...
25+
};
26+
27+
const deployment = new k8s.apps.v1.Deployment("echoserver", {
28+
metadata: {
29+
namespace: ...
30+
},
31+
spec: {
32+
selector: {
33+
matchLabels: appLabels
34+
},
35+
replicas: 1,
36+
template: {
37+
metadata: {
38+
labels: appLabels
39+
},
40+
spec: {
41+
// echoserver container image nutzen
42+
...
43+
}
44+
}
45+
}
46+
}, opts);
47+
48+
const service = new k8s.core.v1.Service("echoserver", {
49+
metadata: {
50+
namespace: ...
51+
},
52+
spec: {
53+
selector: appLabels,
54+
ports: [{
55+
// tcp Port 80 auf Containerport 80
56+
...
57+
}],
58+
type: k8s.core.v1.ServiceSpecType.LoadBalancer // wir verzichten im Beispiel auf einen Ingress Controller und verwenden direkt einen Loadbalancer für den Service
59+
}
60+
}, opts);
61+
62+
export const echoServerIp = ... // Tip: Lässt sich über den Status des Kubernetes Service abfragen.
63+
```
64+
65+
:muscle: Führe `pulumi up` aus und prüfe, ob der Service unter `choServerIp` erreichbar ist.

Lab11/Tasks.md

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Lab 11 - ComponentResource für Kubernetes Deployment & Service
2+
3+
## Überblick
4+
5+
In dieser Übung werden wir eine Pulumi ComponentResource erstellen, die uns ein Kubernetes Deployment zusammen mit einem Service kapselt und als neue Resource in unserem Pulumi Programm zur Verfügung stehen wird. Ziel dieser Übung ist es, das Deployment und den Service aus Lab10 komfortabler nutzen zu können:
6+
7+
```ts
8+
const echoServer = new QuickService("echoserver", {
9+
image: "ealen/echo-server",
10+
labels: appLabels,
11+
name: "echoserver",
12+
namespace: namespace.metadata.name,
13+
port: 80,
14+
targetPort: 80,
15+
replicaCount: 1
16+
}, opts);
17+
```
18+
19+
Das Beispiel soll zeigen, dass man durch Verwendung einer ordentlichen Programmiersprache in der Lage ist, sich selbst Infrastruktur-Bibliotheken aufzubauen.
20+
21+
### Neues Projekt erstellen
22+
23+
1. Ein neues Pulumi Projekt mit Namen `lab11` erstellen: `pulumi new kubernetes-typescript`
24+
2. Eine neue Datei `quickservice.ts` im Projektverzeichnis erstellen.
25+
26+
### Die ResourceArgs unserer Komponente
27+
28+
Da jede Pulumi Resource demsleben Muster folgt, greifen wir dieses hier natürlich ebenfalls auf. Wir definieren hierzu ein `interface` namens `QuickServiceArgs` und fügen alle gewünschten Parameter hinzu:
29+
30+
```ts
31+
export interface QuickServiceArgs {
32+
labels: pulumi.Input<{ [key: string]: pulumi.Input<string>; }>;
33+
namespace: ...;
34+
name: ...;
35+
image: ...;
36+
port: ...,
37+
targetPort: ...,
38+
replicaCount: ...;
39+
};
40+
```
41+
42+
:muscle: Versucht, die notwendigen Typen zu ergänzen, in dem Ihr die Deployment und Service Resourcen, die wir in Lab10 verwendet haben, genauer untersucht.
43+
44+
### QuickService ComponentResource
45+
46+
Unser `QuickService` erweitert eine `pulumi.ComponentResource`. Die Outputs einer Komponente werden als Property angegeben und müssen zum Schluss mit einem Aufruf `this.registerOutputs()` registriert werden. Wir verwenden die übergebenen `pulumi.ComponentResourceOptions` und erstellen daraus eine neue Version, die zusätzlich die `parent` Property auf `this` (also die QuickService Komponente) setzt. Das führt dazu, dass die im weiteren Verlauf erzeugten Resourcen als Kindresourcen unserer Komponente gesehen werden.
47+
48+
```ts
49+
export class QuickService extends pulumi.ComponentResource {
50+
51+
public serviceIp: pulumi.Output<string>; // Ein Output unserer Komponente
52+
53+
constructor(name: string,
54+
args: QuickServiceArgs,
55+
opts: pulumi.ComponentResourceOptions = {}) {
56+
57+
super("spartakiade:codedevote:QuickService", name, args, opts);
58+
59+
const parentOpts = { parent: this, ...opts };
60+
61+
const deployment = new k8s.apps.v1.Deployment(..., {
62+
...
63+
}, parentOpts);
64+
65+
const service = new k8s.core.v1.Service(..., {
66+
...
67+
}, parentOpts);
68+
69+
this.serviceIp = ...;
70+
71+
// erforderlicher Aufruf am Ende, um die definierten Outputs der Komponente zu registrieren
72+
this.registerOutputs();
73+
}
74+
}
75+
```
76+
77+
:muscle: Fülle die Lücken im Code aus.
78+
79+
### Die Komponente in Aktion
80+
81+
Vervollständige nun das Pulumi Programm und nutze den `QuickService`.

Lab12/Tasks.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Lab 12 - Helm Charts
2+
3+
## Überblick
4+
5+
In dieser Übung werden wir eine Wordpress Instanz via Helm Chart deployen. Helm ist recht populär und man findet viele Workloads als Helm Charts. Die Verwendung in Pulumi Programmen ist recht einfach und hat den Vorteil, dass wiederum Outputs anderer Resourcen wieder direkt als Inputs in den Helm Chart einfließen können.
6+
7+
### Neues Projekt erstellen
8+
9+
1. Ein neues Pulumi Projekt mit Namen `lab12` erstellen: `pulumi new kubernetes-typescript`
10+
2. Das npm Paket `@pulumi/random` hinzufügen
11+
12+
### Aufgaben
13+
14+
1. KubeConfig aus Lab7 benutzen und KubernetesProvider erstellen.
15+
2. Kubernetes Namespace `lab12` erstellen.
16+
3. Ein `RandomPassword` erstellen, das initial für den Wordpress Admin User gesetzt wird.
17+
4. Helm-Chart erstellen. Siehe nachfolgendes Codegerüst.
18+
19+
```ts
20+
21+
const wordpress = password.result.apply(pw => new k8s.helm.v3.Chart("wp", {
22+
version: "11.0.9",
23+
namespace: namespace.metadata.name,
24+
chart: "wordpress",
25+
fetchOpts: {
26+
repo: "https://charts.bitnami.com/bitnami",
27+
},
28+
values: {
29+
wordpressUsername: "rooty",
30+
wordpressPassword: ... // das zuvor erzeugte Random Password
31+
}
32+
}));
33+
34+
const frontend = wordpress.apply(x => x.getResourceProperty("v1/Service", "lab12", "wp-wordpress", "status"));
35+
const ingress = frontend.loadBalancer.ingress[0];
36+
37+
export const frontendIp = ... // ingress IP als Output
38+
export const wpUser = ... // als normalen Output!
39+
export const wpPassword = ... // als pulumi Secret !
40+
```
41+
42+
:muscle: Führe `pulumi up` aus und prüfe, ob unter `frontendIp` eine Wordpress Instanz erreichbar ist. Logge dich ins Admin Menü ein.

0 commit comments

Comments
 (0)