With that, let's leave the world of volumes
and images and copying stuff around and folders and files,
and instead, let's dive into the second,
arguably a bit shorter and easier concept,
I wanna discuss in this module.
And that would be arguments and environment variables,
and that's no typo in the title here.
Instead, I'm talking about two options
you can set in your Dockerfile
and on your docker build and docker run commands
because Docker supports build-time arguments
and runtime environment variables.
Now what do I mean by that?
Arguments allow you to set flexible bits of data,
variables you could say,
in your Dockerfile which you can use in there
to pluck different values
into certain Dockerfile instructions
based on arguments that are provided
with the --build-arg option when you run docker build.
And we'll see this in action in a couple of seconds.
Environment variables on the other hand
are available inside of a Dockerfile like arg,
but args are available in your entire application code
in your running application
and you can set them with the env option
inside of a Dockerfile,
telling Docker that you're expecting
this environment variable to be existent
and then provide concrete values
with the --env option on docker run.
And args and environment variables
allow you to create more flexible images and containers
because you don't have to hard-code everything
into these containers and images.
Instead, you can set it dynamically when you build an image
or even only when you run a container.
Now that might still be a bit abstract,
so let's see it in action.
Now one example I wanna start with here
would be in server JS, the port on which we're listening.
This is port 80,
and that's the default port for HTTP requests,
but during development or for whatever reason,
we might wanna change this,
or we might even have
bigger blocks of code in our application code,
which should run differently
based on input provided from outside,
which still might sound very cryptic.
But let's simply start and it'll make more sense.
Node embraces the concept of environment variables
and you access them in your node code
on a globally available process object.
On that object, you have an env key,
and in there, you can access environment variables
that have been set for the environment
in which this code executes.
And now that's the part you can do with Docker.
You can set such globally available environment variables.
And most programming languages and tools
have some kind of support for such environment variables.
So in this case, for example,
we could expect to get a PORT environment variable,
and typically they're written all uppercase,
which then contains the actual PORT number
that should be used to listen on.
Now if I saved this,
at the moment it wouldn't work though,
because at the moment, this environment variable is not set.
We can set it or announce it
inside of the Dockerfile though.
There we could specify it, maybe here,
by adding the env instruction.
And after env,
you provide the name of the environment variable
which you wanna announce.
In this case, PORT.
As a second argument,
you will set a default value for this environment variable,
for example, 80.
And with that, I ensure that this PORT environment variable
is available in this entire application environment
and that it has a default value of 80.
We can now actually
also use this environment variable here on expose.
Do not hard-code 80 here, but expose PORT.
This is now possible
because it is a registered environment variable here.
However, the syntax is actually not like this.
Instead, you need to add a dollar sign in front of it,
telling Docker that the thing after the dollar sign
is the name of an environment variable.
And with that,
Docker will look for this PORT environment variable
and pluck the value stored in there, in here.
Now with that,
we can first of all rebuild our image.
And I'm going to give it a tag of env.
So build that image.
And thereafter, of course,
also run our container again with the docker run command
to be used all the time,
this time with the env tag here after the image though.
Now I'm still publishing the internal PORT 80 here
because I know that this is the default for this container.
So this should still work.
If I now hit enter,
I'm getting an error that this container is still running,
so let me quickly stop that first.
Then repeat this and hit enter
and everything works as before.
Now the advantage of using environment variables
is that we now can configure this.
When we run this container though,
we're not limited to this hard-coded value.
We just have a default value here,
but we don't have to stick to that.
So again, I can stop this container
and then run this again, but now with an extra option
which I set here.
Let's say here.
You can add the --env option,
and after that,
you can add an environment variable key value pair.
And we can set PORT
equal to 8,000, let's say, like this.
And you can add multiple environment variables here
if you want to, but I'm just setting this.
And of course, this also means
that we now need to expose the internal PORT 8,000
because since we set the environment variable to that,
this 8,000 PORT will be used here and also in the server JS.
But now we don't need to rebuild the image
just to change the PORT.
Thanks to the environment variable,
we can just do it like this in the run command.
And if I start that and reload, it still works,
which means that setting this new PORT was successful.
Now you've got a couple of options
when it comes to setting them on the docker run command.
I showed you --env.
You can also shorten this to just dash E if you want to.
That's also supported.
And if you have multiple environment variables,
you'll simply add multiple dash Es with the key value pairs,
just as we did it for volumes, basically.
There we also had multiple dash V flex.
You can also specify,
if I stop this container, you can also specify a file
that contains your environment variable
if you prefer this.
Often such a file is named .env,
but you don't have to name it like this,
but here I will do that.
And then in this file, you could set up
your environment variable key value pair,
so PORT set to 8,000.
And then you could also run this container
and instead of adding the environment variable here,
you could also just use the --env-file option now,
instead of just --env or -e
and point at that file
that contains your environment variables.
In this case, that's the .env file.
It's in the same folder as I'm currently navigated in
in my terminal here.
And then therefore you should start with dot slash,
which means the .env file in the folder
in which I'm currently in here in my terminal.
And with that, the values will be read in from that file.
And hence this still works if we reload here
because now PORT is still set to 8,000.
The advantage of using such a file could be
that you can always rerun the same command
and just switch your values here in the file,
instead of having to do that in the docker run command.
That's why you might wanna use such a file,
but ultimately it's of course up to you
which approach you prefer.
But it should be clear
why environment variables can be helpful.
They help us run one and the same container
based on one and the same image in different modes,
in different configurations, you could say.
So let me now stop feedback app again, and let's continue.