forked from sdouche/presentation-docker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
853 lines (692 loc) · 18.9 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="keywords" content="remark,remarkjs,markdown,slideshow,presentation" />
<meta name="description" content="A simple, in-browser, markdown-driven slideshow tool." />
<title>Introduction à Docker</title>
<link rel="stylesheet" type="text/css" href="theme.css">
</head>
<body>
<textarea id="source">
name: inverse
layout: true
class: center, middle, inverse
---
# Introduction à Docker
## Sébastien Douche — @sdouche
.footnote[https://github.com/sdouche/presentation-docker]
---
layout: false
.left-column[
## Qui suis je ?
]
.right-column[
39 ans. Français. Pas très intelligent mais j'aime comprendre.
- Geek depuis 1984
- Fan de Logiciels Libres depuis 1995
- Développeur (Python, Go, Dart, Rust)
- Sysadmin (Linux / BSD)
- Responsable technique chez un éditeur logiciel français depuis 2007
- Speaker (Git, Python, Go, Dart, organisation, management...)
- Intéressé par le Lifehacking
- Adore les jeux de sociétés modernes
- Motard (Honda CBR RR)
- Aime l'humour noir, le second degré et les blagues pourries
]
---
template: inverse
# Objectif
---
class: center, middle
Automatiser le déploiement d'environnements sous forme de conteneurs *légers*, *portables* et *auto-suffisants*.
.footnote[http://www.docker.io]
---
class: center, middle
## Quel est le problème ?
![](img/the_challenge.jpeg)
---
class: center, middle
## La solution Docker
![](img/docker_container.jpeg)
---
class: center, middle
![](img/container.jpeg)
---
class: center, middle
![](img/container2.jpeg)
---
template: inverse
# Histoire du conteneur
---
class: middle
Le premier bateau porte-conteneur, le Ideal-X, part le 26 avril 1956 du port de Newark (New Jersey) vers le port de Houston (Texas). A son bord, 58 conteneurs de 35 pieds.
.footnote[35 pieds était le standard USA des camions]
---
class: center, middle
![](img/ideal-x.jpeg)
---
class: middle
Invention de Malcom McLean (1914-2001), magnat dans le transport routier, qui avait calculé que le coût passerait de 5.83$ la tonne à 0.16$ en passant par Ideal-X. Les containeurs ont donc **réduit les coûts de transport cargo de 90%**.
Il fonda la société SeaLand, rachetée en 1999 par Maersk, leader mondial du conteneur.
---
class: center, middle
![](img/book.jpeg)
---
template: inverse
# Caractéristiques d'un conteneur
---
class: center, middle
## Agnostique sur le contenu
---
class: center, middle
## Agnostique sur le transporteur
---
class: center, middle
## Isolation
---
class: center, middle
## Automatisation
---
template: inverse
# Docker
---
## Projet jeune
* 18/01/2013 : 1er commit
* 01/02/2013 : 1ere démo en ligne
* 21/03/2013 : 1ere démo à Pycon US
* 23/03/2013 : .blue[Version 0.1]
* 26/03/2013 : Ouverture du dépôt GitHub
* 23/04/2013 : .blue[Version 0.2]
* 06/05/2013 : .blue[Version 0.3]
* 03/06/2013 : .blue[Version 0.4]
* 25/06/2013 : Rejoint la fondation Linux
* 18/07/2013 : .blue[Version 0.5] (top, mount)
* 23/08/2013 : .blue[Version 0.6] (-privileged, LXC conf)
* 19/09/2013 : Partenariat avec Red Hat
* 29/10/2013 : Société renommée en Docker
* 26/11/2013 : .blue[Version 0.7] (noyau standard, device-mapper, name, links)
* 21/01/2014 : Levée de 15M$
* 04/02/2014 : .blue[Version 0.8] (MacOSX, BTRFS experimental, ONBUILD)
---
## Mais très actif
Dans le Top 15 sur GitHub.
Au 25/09/2013: 3389 commits, 975 PR et 169 contributeurs.
Au 13/02/2014: 6183 commits, 4103 PR et 334 contributeurs.
---
## Pré-requis
* Kernel 3.8+ (avec Cgroups et namespaces) ou RHEL 2.6.32
* AUFS (ou device-mapper / VFS)
* LXC
* 64 bits
http://docs.docker.io/en/latest/installation/
---
template: inverse
# LXC
---
class: center, middle
## Permet d'.blue[isoler] l'exécution des applications dans des contexte d'éxécution (VE).
### "chroot on steroids”
---
class: center, middle
![](img/archiisolateur.png)
---
class: center, middle
## L'intérêt du conteneur est son faible footprint
---
template: inverse
## Namespace
---
class: center, middle
## Service fournit par le noyau Linux pour gérer l'isolation
---
## Le Mount namespace (Linux 2.4.19)
Gère l'isolation des points de montage du système de fichier vus par un groupe de process :
* les points de montage ne sont plus globaux mais spécifiques au namespace
* les points de montage peuvent être propagés
* racine propre (chroot)
---
## Le PID namespace (Linux 2.6.24)
Gère l'isolation des ID de process :
* PID 1 init-like par namespace
* chaque namespace a sa propre numération PID (isolation de l'hôte)
* le process d'un namespace ne peut envoyer de systemcall sur un autre process d'un autre PID namespace
* gestion de pseudo-filesystem (ex : /proc) vu par le PID namespace qui le monte
* un process possède plusieurs PID : un dans le namespace, un en dehors (process vu par l'hôte), davantage en cas de namespaces imbriqués
---
## Le Net namespace (Linux 2.6.19-2.6.24)
Gère l'isolation du réseau. Chacun possèdant :
* ses interfaces
* ses ports
* sa table de routage
* ses règles de firewall (iptables)
* son répertoire /proc/net
* INADDR_ANY (0.0.0.0)
.footnote[Il est possible de créer des «pair interfaces» (visibles de l'intérieur et de l'extérieur)]
---
## Le User namespace (Linux 2.6.23-3.8)
Gère l'isolation des utilisateurs et des groupes en :
* séparant les droits selon les différents namespaces
* rendant sûr le partage de namespace à des process sans privilège
---
## Le IPC namespace (Linux 2.6.19-2.6.30)
Gère l'isolation des ressources IPC :
- semaphores
- message queues
- shared memory segments
.footnote[Depuis Linux 2.6.30, il gère aussi les files de messages POSIX]
---
## Le UTS namespace (Linux 2.6.19)
Gère l'isolation des identifiants de nom et de domaine.
UTS vient de la structure "utsname" passée à l'appel système uname(). UTS voulant dire "UNIX Time-sharing System".
---
template: inverse
## Control Groups (cgroups)
---
class: center, middle
## Service fourni par le noyau pour gérer la limitation de ressource
---
class: center, middle
## On peut voir cela comnme un ulimit pour un groupe de process.
---
class: center, middle
## Très pratique car permet de suivre finement des process (systemd l'utilise) et plus généralement pour limiter vos process.
---
## Pseudo-fichiers pour manipuler le groupe
```bash
# root@srv1:/sys/fs/cgroup# ls -1
blkio
cpu
cpuacct
cpuset
devices
freezer
hugetlb
memory
perf_event
```
---
## Installation de LXC
```bash
$ sudo aptitude install lxc lxc-templates
```
---
## Templates
```bash
$ dpkg -L lxc-templates
/usr/share/lxc/templates/lxc-altlinux
/usr/share/lxc/templates/lxc-oracle
/usr/share/lxc/templates/lxc-sshd
/usr/share/lxc/templates/lxc-debian
/usr/share/lxc/templates/lxc-alpine
/usr/share/lxc/templates/lxc-opensuse
/usr/share/lxc/templates/lxc-fedora
/usr/share/lxc/templates/lxc-archlinux
/usr/share/lxc/templates/lxc-busybox
/usr/share/lxc/templates/lxc-ubuntu
/usr/share/lxc/templates/lxc-ubuntu-cloud
```
---
## Verification du noyau
```bash
$ sudo lxc-checkconfig
Kernel configuration not found at /proc/config.gz; searching...
Kernel configuration found at /boot/config-3.8.0-31-generic
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: missing
Network namespace: enabled
Multiple /dev/pts instances: enabled
--- Control groups ---
Cgroup: enabled
Cgroup clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled
--- Misc ---
Veth pair device: enabled
Macvlan: enabled
Vlan: enabled
File capabilities: enabled
```
---
## Exemple de création de VM
```bash
$ sudo lxc-create -n test -t ubuntu
Checking cache download in /var/cache/lxc/raring/rootfs*amd64 ...
Downloading ubuntu raring minimal ...
I: Retrieving InRelease
I: Failed to retrieve InRelease
I: Retrieving Release
I: Retrieving Release.gpg
...
'ubuntu' template installed
'test' created
```
---
## Lancement
```bash
$ sudo lxc-start -name test
```
---
template: inverse
# AUFS
---
class: middle
## Supporte le mode union
```bash
$ mount -t aufs -o dirs=/path/to/files1:/path/to/files2 none /path/to/files
```
## Supporte le Copy On Write (COW)
```bash
$ mount -t aufs -o br=/tmp=rw:/bin:ro /srv
```
---
template: inverse
# Docker
---
## Terminologie
Quelques mots clés :
* index : répertoire public (https://index.docker.io/)
* image : conteneur en lecture seule (snapshot)
* conteneur : élement manipulable
* run : créer un conteneur (à partir d'une image)
---
## Installation Ubuntu
```bash
sudo sh -c "curl https://get.docker.io/gpg | apt-key add -"
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main \
> /etc/apt/sources.list.d/docker.list"
sudo apt-get update
sudo apt-get install lxc-docker
```
*Note* : Docker est écrit en Go, cela veut dire qu'il n'installe qu'un binaire.
---
## Lancement de Docker
```bash
$ sudo /usr/bin/docker -d &
```
---
## Vérification de l'installation
```xml
$ docker
Usage: docker [OPTIONS] COMMAND [arg...]
A self-sufficient runtime for linux containers.
Commands:
attach Attach to a running container
build Build a container from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders from the containers filesystem to the host path
diff Inspect changes on a container's filesystem
events Get real time events from the server
export Stream the contents of a container as a tar archive
history Show the history of an image
images List images
import Create a new filesystem image from the contents of a tarball
info Display system-wide information
insert Insert a file in an image
inspect Return low-level information on a container
kill Kill a running container
login Register or Login to the docker registry server
logs Fetch the logs of a container
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
top Lookup the running processes of a container
ps List containers
...
```
---
## Commande search
Rechercher une image :
```xml
$ sudo docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL TRUSTED
stackbrew/ubuntu XXX 34
...
crashsystems/gitlab-docker XXX 11 [OK]
dockerfile/ubuntu XXX 7 [OK]
...
```
Officiel : provient de la société Docker
Trusted : traçabilité
---
## Commande pull
Récupération d'une image Ubuntu (par défaut avec le tag *lastest*) :
```xml
$ sudo docker pull stackbrew/ubuntu
Pulling repository stackbrew/ubuntu
3aa646e4f1d2: Download complete
0e5997dad26c: Download complete
ddc094db4e2b: Download complete
24ba2ee5d982: Download complete
511136ea3c5a: Download complete
b74728ce6435: Download complete
46e4dee27895: Download complete
cc7385a89304: Download complete
0ce1be727978: Download complete
```
---
## Commande history
Vérification de son contenu :
```xml
$ sudo docker history stackbrew/ubuntu
IMAGE CREATED CREATED BY SIZE
3aa646e4f1d2 8 weeks ago /bin/sh -c #(nop) ADD p... 125.9 MB
b74728ce6435 8 weeks ago /bin/sh -c #(nop) MAINT... 0 B
511136ea3c5a 8 months ago 0 B
```
---
## Commande images
Lister les images :
```xml
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
stackbrew/ubuntu 13.10 24ba2ee5d982 8 weeks ago 144.6 MB
stackbrew/ubuntu saucy 24ba2ee5d982 8 weeks ago 144.6 MB
stackbrew/ubuntu raring 0e5997dad26c 8 weeks ago 133.6 MB
stackbrew/ubuntu 13.04 0e5997dad26c 8 weeks ago 133.6 MB
stackbrew/ubuntu 12.10 ddc094db4e2b 8 weeks ago 127.6 MB
stackbrew/ubuntu quantal ddc094db4e2b 8 weeks ago 127.6 MB
stackbrew/ubuntu 12.04 3aa646e4f1d2 8 weeks ago 125.9 MB
stackbrew/ubuntu latest 3aa646e4f1d2 8 weeks ago 125.9 MB
stackbrew/ubuntu precise 3aa646e4f1d2 8 weeks ago 125.9 MB
```
---
## Commande run (1)
Lancement d'un shell :
```xml
sudo docker run -i -t stackbrew/ubuntu /bin/bash
root@419eed6ff306:/#
```
---
## Commande run (2)
Lancer une commande :
```xml
$ sudo docker run stackbrew/ubuntu /bin/echo hello world
hello world
```
---
## Commande run (3)
Lancer une application :
```xml
$ ID=$(sudo docker run -d stackbrew/ubuntu /bin/sh \
-c "while true; do echo hello world; sleep 1; done")
$ echo $ID
f684fc88aec3
```
---
## Commande run (4)
On peut nommer un conteneur :
```xml
$ sudo docker run -d -name redis sdouche/redis
```
---
## Commande run (5)
Et lier deux conteneurs :
```xml
$ sudo docker run -t -i -link redis:db -name webapp ubuntu bash
```
---
## Commande ps
Lister les conteneurs lançés :
```xml
$ sudo docker ps
ID IMAGE COMMAND CREATED
f684fc88aec3 stackbrew/ubuntu:latest /bin/sh *c while tru 33s ago
```
**Note** : option -a pour voir tous les conteneurs.
---
## Commande logs
Afficher la console :
```xml
$ docker logs f684fc88aec3
hello world
hello world
hello world
hello world
hello world
```
---
## Commande attach
Attacher un conteneur :
```xml
$ docker attach f684fc88aec3
hello world
hello world
hello world
```
---
## Commande stop
Arrêter un conteneur :
```xml
$ docker stop f684fc88aec3
```
**Note** : la commande pour lancer est... start.
---
## Exposer un port
Associer un port du conteneur avec un port de la machine hôte :
```xml
$ sudo docker run -d -p 8888:80 ubuntu
```
**Note** : par défaut, les ports du conteneur ne sont accessibles que depuis la machine hôte
---
## Exposer un volume
Monter le répertoire d'un autre conteneur :
```xml
$ ID=(sudo docker run -d -v /srv stackbrew/ubuntu)
$ sudo docker run -d -volumes-from=$ID stackbrew/ubuntu
```
---
## Commande commit
Enregistre la différence entre l'image et le conteneur :
```xml
$ sudo docker run -i -t stackbrew/ubuntu /bin/bash
root@419eed6ff306:/# apt-get install nginx
...
$ sudo docker commit -m "Ubuntu with Nginx" f684fc88aec3 sdouche/nginx
```
---
template: inverse
# Dockerfile
---
class: center, middle
## Langage de script pour automatiser la création d'images
Tutorial : http://www.docker.io/learn/dockerfile/
---
## Exemple simple
```xml
FROM ubuntu:quantal
MAINTAINER Sebastien Douche [email protected]
RUN echo "deb http://fr.archive.ubuntu.com/ubuntu quantal main " \
> /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y nginx
ENTRYPOINT ["nginx"]
EXPOSE 80
```
---
## Résultat
```xml
$ sudo docker build -t sdouche/nginx .
Uploading context 10240 bytes
Step 1 : FROM ubuntu
---> 8dbd9e392a96
Step 2 : MAINTAINER Sebastien Douche [email protected]
---> Using cache
---> 1ed956422d1e
Step 3 : RUN echo "deb http://fr.archive.ubuntu.com/ubuntu quantal main"
> /etc/apt/sources.list
---> Running in 0f306df45690
---> 769ee79eb920
Step 4 : RUN apt-get update
---> Running in ab6e03a4b456
...
---> 70c4d6981ec2
Step 5 : RUN apt-get install -y nginx-full
---> Running in 4f9b62e09cef
...
---> 3fdbac5a8b0b
Step 6 : ENTRYPOINT ["nginx"]
---> Running in 887a4e981b5b
---> 641d26bd702a
Step 7 : EXPOSE 80
---> Running in fedd77ac26f7
---> 9d0045d5fa7a
Successfully built 9d0045d5fa7a
```
---
## Commande diff
Affiche les différences avec le conteneur père :
```xml
$ sudo docker diff 769ee79eb920
2013/10/05 03:01:25 GET /v1.5/containers/769ee79eb920/changes
C /dev
A /dev/kmsg
C /etc/apt/sources.list
```
---
## Commande push
Pousser une image sur l'index (ici avec le compte sdouche) :
```xml
$ sudo docker push sdouche/nginx
```
---
## Commande import / export
Exporter :
```xml
$ sudo docker export 9d0045d5fa7a > container-nginx.tgz
```
Importer :
```xml
$ sudo docker import http://example.com/image.tgz example
$ cat example.tgz | sudo docker import - example
$ sudo tar -c . | docker import - exampledir
```
---
## Documentation CLI
Liste des commandes :
http://docs.docker.io/en/latest/reference/commandline/
---
## API
http://docs.docker.io/en/latest/reference/api/
* API REST
* Feed des evenements
* Websocket
**Note** : la CLI n'est qu'un client pour l'API
---
## Clients
* Python (docker-py)
* Ruby (docker-client, docker-api)
* Javascript (docker.io, docker-js, dockerui)
* Java (docker-java)
* Erlang (erldocker)
* Go (go-dockerclient)
---
## Exemple avec (docker-py) Python
```python
import docker
# create client
docker_client = docker.Client(base_url='unix://var/run/docker.sock',
version="1.4")
# create container
container = docker_client.create_container('ubuntu', None, detach=True)
container_id = container.get('Id')
# start Container
docker_client.start(container_id)
# get Ip address
meta = docker_client.inspect_container(container_id)
ip = meta.get('NetworkSettings').get("IPAddress")
# stop container
docker_client.stop(container_id)
```
---
## Docker Index
Dépôt public des images (+ metadonnées)
https://index.docker.io/
---
## Registry
Index privé
https://github.com/dotcloud/docker-registry
---
template: inverse
# Ecosystème
---
## MacOS
* boot2docker est une distribution Linux légere (~27MB en RAM et se lance en ~5s), dérivée de la distribution Tiny Core Linux et conçue pour Docker.
http://boot2docker.io/
---
## GUI
* Dockland - Yet another docker web UI
https://github.com/dynport/dockland
* Shipyard – a web UI for Docker
https://github.com/ehazlett/shipyard
* DockerUI – Web interface to interact with the Docker Remote API
https://github.com/crosbymichael/dockerui
---
## Hébergement
* flynn
https://flynn.io/
* Orchard
https://orchardup.com/
* Stardock
https://stackdock.com/
* Tutum
http://www.tutum.co/
* Quay
https://quay.io/
---
## Orchestration
* Serf
http://www.serfdom.io/
* Maestro NG
https://github.com/signalfuse/maestro-ng
* Shipper
https://github.com/mailgun/shipper
---
## Intégration continue
* Shippable
https://www.shippable.com/
* Drone
https://github.com/drone/drone
---
## Environnement de dev
* fig
http://orchardup.github.io/fig/
---
## Autres
* IAAS : OpenStack
* SCM : Chef / Puppet / Salt / Ansible
* OS : CoreOS
---
## Docker 1.0
Ce qui est prévu :
* Architecture pluggable
* Support OpenVZ, FreeBSD Jails, Solaris Zones
* Meilleur support des distributions non Ubuntu
* Support de BTRFS (déjà là en beta)
* Intégration avec Libvirt
* Gestion des Index privés payants sur docker.io
---
template: inverse
# Démo
---
template: inverse
## That's all folks!
</textarea>
<script src="remark.min.js" type="text/javascript"></script>
<script type="text/javascript">
var hljs = remark.highlighter.engine;
</script>
<script src="remark.language.js" type="text/javascript"></script>
<script type="text/javascript">
var slideshow = remark.create({
highlightStyle: 'monokai',
highlightLanguage: 'remark'
}) ;
</script>
</body>
</html>