Create a Docker Image from CentOS Minimal ISO
When we are dockerizing an ASP .NET Core application, there will be a file called Dockerfile. For example, the Dockerfile in my previous project, Changshi, has the following content.
FROM microsoft/aspnetcore:2.0 ARG source WORKDIR /app EXPOSE 80 COPY ${source:-obj/Docker/publish} . ENTRYPOINT ["dotnet", "changshi.dll"]
The Dockerfile basically is a set of instructions for Docker to build images automatically. The FROM instruction in the first line initializes a new build stage and sets the Parent Image for subsequent instructions. In the Dockerfile above, it is using microsoft/aspnetcore, the official image for running compiled ASP .NET Core apps, as the Parent Image.
If we need to control the contents of the image, then one way that we can do is to create a Base Image. So, in this post, I’m going to share about my journey of creating a Docker image from CentOS Minimal ISO.
STEP 1: SETTING UP VIRTUAL MACHINE ON VIRTUALBOX
We can easily get the minimal ISO of CentOS on their official website.
After successfully downloading the minimal ISO, we need to proceed to launch the Oracle VM VirtualBox (Download here if you don’t have one).
For Windows users who have Hyper-V enabled because of Docker for Windows, please disable it first otherwise you will either not able to start a VM with 64-bit guest OS even though your host OS is 64-bit Windows 10 or simply encounter a BSOD.
Funny thing is that after switching off Hyper-V, Docker for Windows will make noise saying that it needs Hyper-V to be enabled to work properly. So currently I have to keep switching on and off the Hyper-V feature option depends on which tool I’m going to use.
There is one important step on running CentOS on the VM. We need to remember to configure the Network of the VM to use network adapter attached to “Bridged Adapter”. This is to connect the VM through the host to whatever is our default network device that allocates IP addresses for our physical network. Doing so will help us to retrieve the Docker image tar file via SCP later.
Then in the Network & Host Name section of the installation, we shall see the IP address allocated to the VM.
To verify whether it works or not, we simply need to use the following command to check if an IP address is successfully allocated to the VM or not. In the minimal installation of CentOS 7, the command ifconfig is already not in use.
# ip a
We then can get the IP Address which is allocated to the VM. Sometimes, I need to wait for about 5 minutes before it can display the IP address successfully.
STEP 2: INSTALLING DOCKER ON VM
After we get the IP address of the VM, we then can SSH into it. On Windows, I use PuTTY, a free SSH client for Windows, to easily SSH to the VM.
We proceed to install EPEL repository before we can install Docker on the VM.
Since we are going to use wget to retrieve EPEL, we first need to install wget as following.
# yum install wget
Then we can use the wget command to download EPEL repository on the VM.
# wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
The file will be downloaded to the temp folder. So, to install it we will do the following.
# cd /tmp # sudo yum install epel-release-latest-7.noarch.rpm
After the installation is done, there should be a success message as following showing on the console.
Installed: epel-release.noarch 0:7-11 Complete!
Now if we head to /etc/yum.repos.d, we will see the following files.
CentOS-Base.repo CentOS-fasttrack.repo CentOS-Vault.repo CentOS-CR.repo CentOS-Media.repo epel.repo CentOS-Debuginfo.repo CentOS-Sources.repo epel-testing.repo
In the CentOS-Base.repo, we need to enable the CentOS Plus repository which is by default disabled. To do so, we simply change the value of enabled to 1 under [centosplus] section.
Then we can proceed to install docker on the VM using yum.
# yum install docker
STEP 3: START DOCKER
Once docker is installed, we can then start the docker service with the following command.
# service docker start
So now if we list the images and containers inside the docker, the results should be 0 image and 0 container, as shown in the screenshot below.
STEP 4: BUILDING FIRST DOCKER IMAGE
Thanks to the people in Moby Project, a collaborative project for the container ecosystem to assemble container-based systems, we have a script to create a base CentOS Docker image using yum.
The script is now available on Moby Project Github repository.
We now need to create a folder called scripts in the root and then create a file called createimage.sh in the folder. This step can be summarized as the following commands.
# mkdir scripts # cd scripts # vim createimage.sh
We then need to copy-and-paste the script from Moby Project to createimage.sh.
After that, we need to make createimage.sh executable with the following command.
# chmod +x createimage.sh
To run this script now, we need to do as follows, where centos7base is the name of the image file.
# ./createimage.sh centos7base
After it is done, we will see the centos7base image added in docker. The image is very, very small with only 271MB as its size.
STEP 5: ADD SOMETHING (.NET CORE SDK) TO CONTAINER
Since now we have our first Docker image, then we can proceed to create a container with the following command.
# docker run -i -t /bin/bash
We will be brought into the container. So now we can simply add something, such as the .NET Core SDK to the container by following the .NET Core installation steps for CentOS 7.1 (64-bit) which can be summarized as the following commands to execute.
# sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc # sudo sh -c 'echo -e "[packages-microsoft-com-prod]\nname=packages-microsoft-com-prod \nbaseurl=https://packages.microsoft.com/yumrepos/microsoft-rhel7.3-prod\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/dotnetdev.repo' # sudo yum update # sudo yum install libunwind libicu # sudo yum install dotnet-sdk-2.0.0 # export PATH=$PATH:$HOME/dotnet
We then can create a new image from the changes we have done on the container using the following command where the centos_netcore is the repository name and 1.0 is its tag.
docker commit [centos_netcore:1.0]
We will then realize the new image container will be quite big with 1.7GB as its size. Thanks to .NET Core SDK.
STEP 6: MOVING THE NEW IMAGE TO PC
The next step that we are going to do is exporting the new image as a .tar file using the following command.
docker save > /tmp/centos_netcore.tar
Now, we need to launch WinSCP to retrieve the .tar file via SCP (Secure Copy Protocol) to local host.
STEP 7: LOAD DOCKER IMAGE
So now we can shutdown the VM and enable back the Hyper-V because the subsequent steps will need Docker for Windows to work.
After restarting our local computer with Hyper-V enabled, we can launch Docker for Windows. After that, we load the image to the Docker using the following command in the directory where we keep the .tar file in local host.
docker load < centos_netcore.tar
STEP 8: RUNNING ASP .NET CORE WEB APP ON THE DOCKER IMAGE
Now, we can change the Dockerfile to use the new image we created.
FROM centos_netcore:1.0 ARG source WORKDIR /app EXPOSE 80 COPY ${source:-obj/Docker/publish} . ENTRYPOINT ["dotnet", "changshi.dll"]
When we hit F5 to make it run in Docker, yup, we will get back the website.
No, just kidding. We will actually get an error message that says localhost doesn’t send any data.
So if we read the messages in Visual Studio Output Window, we will see one line of message saying that it’s unable to bind to http://localhost:5000 on the IPv6 loopback interface.
According to Cesar Blum Silveira, Software Engineer from Microsoft ASP .NET Core Team, this problem is because “localhost will attempt to bind to both the IPv4 and IPv6 loopback interfaces. If IPv6 is not available or fails to bind for some reason, you will see that warning.”
Then I switch to view the output from Docker on the Output Window.
It turns out that the port on docker is port 80. So I tried to add the following line in Program.cs.
public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseUrls("http://0.0.0.0:80") // Added this line .UseStartup() .Build();
Now, it works again with the beautiful web page.
CONTAINERS, CONTAINERS EVERYWHERE
The whole concept of Docker images, containers, micro-services are still very new to me. Hence, if you spot any problem in my post, feel free to point out. Thanks in advance!
Tidak ada komentar:
Posting Komentar