1
00:00:01,802 --> 00:00:04,430
Multi-Stage builds allow you

2
00:00:04,430 --> 00:00:06,810
to have one Dockerfile,

3
00:00:06,810 --> 00:00:09,670
that define multiple build steps

4
00:00:09,670 --> 00:00:13,943
or setup steps, so called "stages" inside of that file.

5
00:00:15,050 --> 00:00:18,620
Stages can copy results from each other,

6
00:00:18,620 --> 00:00:22,610
so we can have one stage to create the optimized files

7
00:00:22,610 --> 00:00:24,923
and another stage to serve them.

8
00:00:26,130 --> 00:00:28,680
We can either build the entire Dockerfile

9
00:00:28,680 --> 00:00:33,180
going through all stages, step by step from top to bottom

10
00:00:33,180 --> 00:00:37,350
or we select individual stages up to which we wanna build,

11
00:00:37,350 --> 00:00:41,070
skipping all stages that would come after them

12
00:00:41,070 --> 00:00:45,510
that are multi-stage builds and multi-stage Dockerfiles.

13
00:00:45,510 --> 00:00:47,940
That's exactly what we can use here.

14
00:00:47,940 --> 00:00:52,300
You can think of this build step here as our first stage.

15
00:00:52,300 --> 00:00:54,800
We grab and install our dependencies,

16
00:00:54,800 --> 00:00:56,580
we grab our source code

17
00:00:56,580 --> 00:00:59,590
and then we build that source code

18
00:00:59,590 --> 00:01:02,390
with the code and the dependencies.

19
00:01:02,390 --> 00:01:07,390
After this step here, we have our finished source code.

20
00:01:07,660 --> 00:01:09,570
Now, with multistage builds,

21
00:01:09,570 --> 00:01:14,350
we just have to use "RUN" instead of command

22
00:01:14,350 --> 00:01:17,530
and therefore just "NPM run build" like this.

23
00:01:17,530 --> 00:01:20,490
Then we can continue with more steps thereafter.

24
00:01:20,490 --> 00:01:23,730
Now, we could do it as in a regular Dockerfile as well.

25
00:01:23,730 --> 00:01:25,700
But now here's the special thing,

26
00:01:25,700 --> 00:01:30,700
I wanna switch to a different base image after this command,

27
00:01:31,220 --> 00:01:34,170
Once we have these optimized files.

28
00:01:34,170 --> 00:01:38,600
Because we only need node to build the optimized files,

29
00:01:38,600 --> 00:01:40,760
because we need the NPM command,

30
00:01:40,760 --> 00:01:42,670
which ships together with node

31
00:01:42,670 --> 00:01:47,150
and because the build script actually also will use node

32
00:01:47,150 --> 00:01:48,910
under the hood.

33
00:01:48,910 --> 00:01:51,540
But once we get these optimized files,

34
00:01:51,540 --> 00:01:53,550
we don't need node anymore,

35
00:01:53,550 --> 00:01:56,250
unless we wanna bring our own node server

36
00:01:56,250 --> 00:01:58,100
to serve these files.

37
00:01:58,100 --> 00:01:59,300
But we don't need to do that,

38
00:01:59,300 --> 00:02:01,370
we could use nginx for that,

39
00:02:01,370 --> 00:02:04,530
which is a very lightweight and slim web server,

40
00:02:04,530 --> 00:02:08,100
which would totally serve our purposes here.

41
00:02:08,100 --> 00:02:10,935
I wanna switch to a different base image

42
00:02:10,935 --> 00:02:14,365
after this run command here.

43
00:02:14,365 --> 00:02:15,577
We can do this.

44
00:02:15,577 --> 00:02:18,530
We can have a second FROM statement here,

45
00:02:18,530 --> 00:02:19,940
effectively turning this

46
00:02:19,940 --> 00:02:22,640
into a multi-stage build Dockerfile.

47
00:02:22,640 --> 00:02:26,330
Because typically, you must only have one base image

48
00:02:26,330 --> 00:02:28,180
but you can indeed switch.

49
00:02:28,180 --> 00:02:31,130
In that case, this previous step you could say,

50
00:02:31,130 --> 00:02:35,470
will be discarded and you will switch to a new base image.

51
00:02:35,470 --> 00:02:37,910
Here, I wanna switch to nginx

52
00:02:37,910 --> 00:02:41,940
and there used the latest stable-alpine version,

53
00:02:41,940 --> 00:02:45,920
which again, is a very slim nginx version.

54
00:02:45,920 --> 00:02:47,960
You can look up these available tags

55
00:02:47,960 --> 00:02:50,973
on the nginx Docker Hub page, of course.

56
00:02:52,010 --> 00:02:55,040
Now here, we wanna do something special though,

57
00:02:55,040 --> 00:02:59,250
we don't want to have our previous changes be discarded.

58
00:02:59,250 --> 00:03:03,683
Instead, we wanna use the optimized files and serve them.

59
00:03:05,280 --> 00:03:09,777
Therefore, you can add a special instruction you could say,

60
00:03:09,777 --> 00:03:12,413
after this FROM instruction here,

61
00:03:12,413 --> 00:03:15,610
after every FROM instruction deed.

62
00:03:15,610 --> 00:03:17,800
You can add the AS keyword

63
00:03:17,800 --> 00:03:20,090
and give this any name of your choice,

64
00:03:20,090 --> 00:03:21,880
like for example build.

65
00:03:21,880 --> 00:03:23,663
But again, this name is up to you.

66
00:03:24,930 --> 00:03:28,700
Then here in our second stage,

67
00:03:28,700 --> 00:03:32,650
so on the second base image in this Dockerfile,

68
00:03:32,650 --> 00:03:36,500
we can copy from this first stage

69
00:03:36,500 --> 00:03:41,500
by using the special "dash dash from" option here

70
00:03:41,580 --> 00:03:43,453
on the copy instruction.

71
00:03:44,670 --> 00:03:46,410
Then you add an equal sign,

72
00:03:46,410 --> 00:03:49,070
and then the stage name from what you wanna copy,

73
00:03:49,070 --> 00:03:51,190
In this case, build.

74
00:03:51,190 --> 00:03:53,970
That means we'll copy the final content

75
00:03:53,970 --> 00:03:55,936
from that build stage.

76
00:03:55,936 --> 00:04:00,470
From all the instructions up to the next FROM instruction

77
00:04:00,470 --> 00:04:02,993
into this new stage here.

78
00:04:04,180 --> 00:04:06,280
Now of course, I don't wanna copy everything

79
00:04:06,280 --> 00:04:08,580
which is in this file system.

80
00:04:08,580 --> 00:04:10,460
After FROM build,

81
00:04:10,460 --> 00:04:13,270
you still need to specify the source path,

82
00:04:13,270 --> 00:04:16,149
just as you did it on copy before as well.

83
00:04:16,149 --> 00:04:19,149
Here we also copied from the local file system

84
00:04:19,149 --> 00:04:22,180
to the working directory inside of the container.

85
00:04:22,180 --> 00:04:24,270
Now here with the FROM option,

86
00:04:24,270 --> 00:04:26,840
we're telling Docker that this copy

87
00:04:26,840 --> 00:04:30,410
will not refer to our local host project folder,

88
00:04:30,410 --> 00:04:34,773
but instead queue the file system from this build stage.

89
00:04:35,660 --> 00:04:37,800
Now here, we can specify a path

90
00:04:37,800 --> 00:04:40,850
in that first build stage file system.

91
00:04:40,850 --> 00:04:44,401
I wanna use "app/build" because...

92
00:04:44,401 --> 00:04:46,780
That's something you need to know.

93
00:04:46,780 --> 00:04:50,840
The built command here in a React project

94
00:04:50,840 --> 00:04:53,160
will create a build folder

95
00:04:53,160 --> 00:04:57,070
which holds these final servable files.

96
00:04:57,070 --> 00:05:00,120
Therefore here I copied from the build stage,

97
00:05:00,120 --> 00:05:03,360
and data from the app/build folder.

98
00:05:03,360 --> 00:05:07,943
Now I wanna copy into the user.

99
00:05:07,943 --> 00:05:12,943
So usr/share/nginx/html folder

100
00:05:15,264 --> 00:05:17,890
here in my nginx image.

101
00:05:17,890 --> 00:05:21,480
That's a special folder for this nginx image.

102
00:05:21,480 --> 00:05:23,170
It is the default folder

103
00:05:23,170 --> 00:05:26,863
from where nginx will try to serve files.

104
00:05:27,910 --> 00:05:30,240
These are always things you can look up

105
00:05:30,240 --> 00:05:32,240
on your official image pages.

106
00:05:32,240 --> 00:05:33,350
They are you, for example,

107
00:05:33,350 --> 00:05:36,800
find that if you wanna host some simple static content,

108
00:05:36,800 --> 00:05:38,830
which is exactly what we have here,

109
00:05:38,830 --> 00:05:42,590
we just have an HTML file and a bunch of JavaScript files,

110
00:05:42,590 --> 00:05:44,520
which is static content.

111
00:05:44,520 --> 00:05:46,720
We just have to host the content

112
00:05:46,720 --> 00:05:50,713
of this user share nginx HTML folder.

113
00:05:51,667 --> 00:05:55,380
Therefore, that's the folder to which we copy here.

114
00:05:55,380 --> 00:05:57,900
Now we're using this multi-stage feature

115
00:05:57,900 --> 00:06:00,470
to copy the result from the first stage

116
00:06:00,470 --> 00:06:02,640
into this new stage.

117
00:06:02,640 --> 00:06:04,300
Now, the final container

118
00:06:04,300 --> 00:06:07,140
will only include that second stage,

119
00:06:07,140 --> 00:06:10,910
but it will first of all build this first stage

120
00:06:10,910 --> 00:06:13,183
to derive this final stage.

121
00:06:14,050 --> 00:06:16,530
You could also have more than one stage

122
00:06:16,530 --> 00:06:18,450
in one at the same Dockerfile.

123
00:06:18,450 --> 00:06:20,950
If you need that you can have as many stages

124
00:06:20,950 --> 00:06:21,930
as you want.

125
00:06:21,930 --> 00:06:25,640
For example, an extra stage for running your tests.

126
00:06:25,640 --> 00:06:26,800
Here however,

127
00:06:26,800 --> 00:06:28,800
I'm happy with copying this.

128
00:06:28,800 --> 00:06:32,618
But now I wanna expose Port 80

129
00:06:32,618 --> 00:06:37,618
because that is the default port nginx exposes internally

130
00:06:37,630 --> 00:06:40,330
so I wanna expose it here as well in my own image,

131
00:06:40,330 --> 00:06:42,093
which is based on nginx.

132
00:06:43,420 --> 00:06:45,780
Then the final command here at the end

133
00:06:45,780 --> 00:06:48,770
is that I wanna start ngnix.

134
00:06:48,770 --> 00:06:52,130
I want to start this nginx server

135
00:06:52,130 --> 00:06:55,360
and ask the official documentation states

136
00:06:55,360 --> 00:06:56,930
if we run it ourselves,

137
00:06:56,930 --> 00:07:01,293
we should add this "dash g, daemon off;" option here.

138
00:07:02,300 --> 00:07:03,790
Therefore, let's do that.

139
00:07:03,790 --> 00:07:08,450
Let's add "dash g, daemon off;"

140
00:07:08,450 --> 00:07:10,933
and don't forget this semicolon at the end.

141
00:07:11,930 --> 00:07:16,030
This is how we should start nginx if we started ourselves,

142
00:07:16,030 --> 00:07:17,240
which we wanna do here,

143
00:07:17,240 --> 00:07:21,653
since we wanna start it after we copied in our custom code.

144
00:07:22,800 --> 00:07:24,760
This is now a brand new feature of course.

145
00:07:24,760 --> 00:07:28,060
We haven't seen multi-stage Dockerfiles before,

146
00:07:28,060 --> 00:07:29,810
but it's a powerful feature,

147
00:07:29,810 --> 00:07:32,680
because it's great for situations like this,

148
00:07:32,680 --> 00:07:36,200
where we have an application which we can serve

149
00:07:36,200 --> 00:07:37,300
the way it is,

150
00:07:37,300 --> 00:07:39,130
but which we need to build first.

151
00:07:39,130 --> 00:07:43,050
Then a multi-stage build is of course awesome.

152
00:07:43,050 --> 00:07:44,710
Now, that we've learned about that

153
00:07:44,710 --> 00:07:48,270
and now that we've build our multi-stage Dockerfile,

154
00:07:48,270 --> 00:07:50,593
let's see how we would deploy that.

