Данная публикация является разбором особенностей контейнерной виртуализации Docker под системой Windows.
Она не претендует на роль исчерпывающей и по мере необходимости будет обновляться и дополняться.
За практическим руководством с нуля советую обратиться к этой публикации.
Содержание
- Предварительные настройки
- Выбор между Docker Toolbox on Windows или Docker for Windows
- Windows контейнеры и Linux контейнеры
- Особенности монтирования папок
- Монтирование с хост-машины или volume
- Особенности разметки диска GPT и MBR
- Docker Toobox to Windows
- Docker Swarm
- Проблемы с кодировкой
- Полезные ссылки
- Заключение
Предварительные настройки
Контейнерная виртуализация или виртуализация на уровне операционной системы Docker нативно работает только на дистрибутивах Linux и FreeBSD (экспериментально).
На Windows вам понадобится гостевая Linux система либо специальная минималистичная виртуальная машина с ядром Linux от разработчиков Docker, которая и ставится из коробки.
Само собой разумеется, что вы включили виртуализацию у себя в BIOS/UEFI
Пункт настройки может называться по-разному: VT-x, VT-d, Intel VT, AMD-V, Virtualization Technology.
Еще одним минимальным системным требованием будет разрядность системы x64 и версия не ниже Windows 7 Pro.
Выбор между Docker Toolbox on Windows или Docker for Windows
Появление Docker Toolbox on Windows и Docker Toolbox on Mac было большим событием.
Сборка включается в себя сам docker, утилиту docker-compose, утилиту для работы с виртуальной машиной docker-machine и клиент Kitematic.
Используется виртуальная машина (по умолчанию на VirtualBox) с минималистичным Linux окружением.
Позже для новых операционных систем выпустили Docker for Windows и Docker for Mac, которая на текущий момент является актуальной версией и продолжает развиваться.
Выбор между версиями не сложный:
— Если у вас Windows 10 x64 Pro, Enterprise или Education то включаем службу Hyper-V и ставим Docker for Windows.
Заметьте, что после включения службы Hyper-V пропадет возможность запускать и создавать x64 виртуальные машины на VirtualBox.
— Если же у вас другая версия Windows(7 Pro, 8, 8.1, 10 Home) то ставим VirtualBox и Docker Toolbox on Windows.
Несмотря на то, что Docker Toolbox разработчиками признан устаревшим работа с ним слабо отличается от Docker for Windows.
Вместе с установкой Docker Toolbox будет создана виртуальная машина.
В самом VirtualBox можно будет добавить оперативной памяти и ядер процессора на ваше усмотрение.
Windows контейнеры и Linux контейнеры
Docker for Windows предоставляет возможность переключать контейнеризацию между Linux и Windows версией.
В режиме Windows контейнеризации вы можете запускать только Windows приложения.
Замечу, что на май 2018 года в официальном Docker Hub существует всего 13 образов для Windows.
После включения Windows контейнеризации не забудьте добавить внешнюю сеть.
В конфигурационном файле docker-compose.yml это выглядит так:
networks:
default:
external:
name: nat
Особенности монтирования папок
На примонтированных volume-ах не кидаются события файловой системы, поэтому inotify-tools не работает.
Спасибо пользователю eee
Если вы разрабатываете свой проект и пользуетесь docker-compose вне домашней папки то вам нужно будет проделать некоторые манипуляции.
Используя Docker for Windows для монтирования нового диска у вашего локального пользователя обязательно должен стоять пароль, который будет использоваться для доступа к shared папки.
Особенность заключается в том, что монтируемые внутрь контейнера диск будет монтироваться как от удаленной машины //10.0.75.1/DISK_DRIVE по протоколу SMB.
Для Docker Toolbox диски монтируются в самом VirtualBox на вкладке «Общие папки»
Пример для диска «D»:
Права доступа к монтируемым файлам и папкам
Как бы вам не хотелось, но для всех примонтированных из хост-машины файлов и папок будут стоять права 755 (rwx r-x r-x) и поменять их вы не сможете.
Остро встает вопрос при монтировании внутрь файла закрытого SSH ключа, права на который должны быть только у владельца(например 600).
В данном случае либо генерируют ключ при создании образа, либо прокидывают сокет ssh-agent с хост-машины.
Монтирование с хост-машины или volume
Монтирование внутрь контейнера происходит с использованием сети и протокола SMB, следовательно, внутри контейнера диск «D:» будет примонтирован из источника //10.0.75.1/D
Использование volume внутри контейнера отображается как монтирование локального диска /dev/sda1, что влияет на скорость работы.
Простым тестом копирование файла на обычном HDD скорость работы получилась следующая:
Такая разница в скорости скорее всего связана с тем, что в volume данные сбрасываются на диск постепенно, задействуя кеш в ОЗУ.
Особенности разметки диска GPT и MBR
Данный пункт не является истинной так как опровергающей или подтверждающей информации в интернете найти не смог.
Если на хост-машине таблица разделов MBR, то контейнер с MySQL/MariaDB может упасть с ошибкой:
InnoDB: File ./ib_logfile101: ‘aio write’ returned OS error 122. Cannot continue operation
По умолчанию в базе данных включеён параметр innodb_use_native_aio, отвечающий за асинхронный ввод/вывод и его надо будет выключить.
Данная проблема также встречается на некоторых версиях MacOS.
Docker Toobox to Windows
Главное правило: начинать работу с запуска ярлыка на рабочем столе «Docker Quickstart Terminal», это решает 80% проблем.
— Бывает возникают проблемы с отсутствия переменных окружения, решается командой:
eval $(docker-machine env default)
— Если все же возникают проблемы из разряда «docker: error during connect», необходимо выполнить:
docker-machine env --shell cmd default
@FOR /f "tokens=*" %i IN ('docker-machine env --shell cmd default') DO @%i
Название Docker Machine по умолчанию default.
Docker Swarm
Ни в Docker for Mac, ни в Docker for Windows — нет возможности использовать запущенные демоны в качестве клиентов кластера (swarm members).
Спасибо пользователю stychos
Проблемы с кодировкой
Используя Docker Toolbox(на Docker for Windows не удалось воспроизвести) нашлась проблема с тем, что русские комментарии в docker-compose.yml файле приводили к ошибке:
Traceback (most recent call last):
File "docker-compose", line 6, in <module>
File "composeclimain.py", line 71, in main
File "composeclimain.py", line 124, in perform_command
File "composeclicommand.py", line 41, in project_from_options
File "composeclicommand.py", line 109, in get_project
File "composeconfigconfig.py", line 283, in find
File "composeconfigconfig.py", line 283, in <listcomp>
File "composeconfigconfig.py", line 183, in from_filename
File "composeconfigconfig.py", line 1434, in load_yaml
File "site-packagesyaml__init__.py", line 94, in safe_load
File "site-packagesyaml__init__.py", line 70, in load
File "site-packagesyamlloader.py", line 24, in __init__
File "site-packagesyamlreader.py", line 85, in __init__
File "site-packagesyamlreader.py", line 124, in determine_encoding
File "site-packagesyamlreader.py", line 178, in update_raw
File "c:projectscomposevenvlibencodingscp1251.py", line 23, in decode
UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 1702: character maps to <undefined>
[4176] Failed to execute script docker-compose
Полезные ссылки
Docker Toolbox on Windows
Docker for Windows
Практическое руководство по Docker
Заключение
Особенности работы с Docker контейнеризацией на системе Windows не отличается от работы на Linux за исключение разобранных выше.
В статье я умышленно не упомянул заметно низкую скорость работы контейнеров и overhead используя систему Windows как само собой разумеющееся.
Буду рад услышать ваши отзывы. Не стесняйтесь предлагать улучшения или указывать на мои ошибки.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какой версией Docker вы пользуетесь?
33.08%
Docker Toolbox on Windows
88
66.92%
Docker for Windows
178
Проголосовали 266 пользователей.
Воздержались 189 пользователей.
Are you new to Docker Windows Images? Are you currently working in a Windows shop and curious to learn about Docker builds for container images? You have come to the right place. The best way to learn about new something is by doing with the docker build
and docker build "tag"
commands!
Not a reader? Watch this related video tutorial!
Not seeing the video? Make sure your ad blocker is disabled.
In this article, you are going to learn how to create your first Windows Docker image from a Dockerfile using the docker build
command.
Let’s get started!
Understanding Docker Container Images
For years, the only way to test or perform development on multiple operating systems (OS) was to have several dedicated physical or virtual machines imaged with the OS version of your choice. This methodology required more hardware and overhead to provision new machines for each software and OS specification.
However, these days the usage of Docker container images has grown partly due to the popularity of micro-service architecture. In response to the rise in Docker’s popularity, Microsoft has started to publicly support Docker images for several flagship products on their Docker Hub page. They have even added native support for images for Windows as a product feature in Windows 10 and Windows Server 2016!
A Docker image is run on a container by using the Docker Engine. Docker images have many benefits such as portability (applicable to multiple environments and platforms), customizable, and highly scalable. As you can see below, unlike traditional virtual machines, the Docker engine runs on a layer between the host OS kernel and the isolated application services that are being containerized.
Understanding Docker Build and Images
The docker build
command can be leveraged to automate container image creation, adopt a container-as-code DevOps practice, and integrate containerization into the development cycle of your projects. Dockerfiles are simply text files that contain build instructions used by Docker to create a new container image that is based on an existing image.
The user can specify the base image and list of commands to be run when a container image is deployed or startup for the first time. In this article, you will learn how to create a Windows-based docker image from Dockerfile using a Windows container.
This process has several benefits over using a pre-built container image:
- You are able to rebuild a container image for several versions of Windows – which is great for testing code changes on several platforms.
- You will have more control over what is installed in the container. This will allow you to keep your container size to a minimum.
- For security reasons, you might want to check the container for vulnerabilities and apply security hardening to the base image
Prerequisites/Requirements
This article is a walkthrough on learning about learning how to build a Docker image using a Dockerfile. If you’d like to follow along, ensure that you have the following prerequisites in place.
- Docker for Windows installed. I’ll be using the Docker Community Edition (CE) version 2.1.0.4 in my environment.
- Internet access is needed for downloading the Docker images
- Windows 10+ Operating System (version 1709 is being used for this tutorial)
- Nested virtualization enabled
- 5 GB of free diskspace on your local machine
- PowerShell 5.0+
- This tutorial uses the Visual Studio Code IDE. However feel free to use what ever IDE you’d prefer.
Note: Be sure to enable Windows Containers Configuration when installing Docker.
Getting Prepared
You’ll first need a folder to store all of the Docker images and containers you’ll be building from those images. To do so, open a Powershell or cmd terminal (you’ll be using PowerShell throughout this article) and create a new directory called C:Containers.
Once the folder is created, change to that directory. This puts the console’s current working directory to C:Containers to default all downloads to this directory.
PS51> mkdir C:Containers
PS51> cd C:Containers
In this article, you’ll get a headstart. Most of the files to work through this project are already available. Once the folder is created, perform a Git pull to copy over the files needed for this article from the TechSnips Github repository to the C:Containers folder. Once complete, check to make sure that the C:Containers folder looks like below.
Downloading the IIS Windows Docker Image
The first task to perform is to download a “template” or base image. You’ll be building your own Docker image later but first, you need an image to get started with. You’ll be downloading the latest IIS and Windows Server Core Images that are required for this tutorial. The updated list of images can be found on the official Microsoft Docker hub image page.
Reviewing the Current Docker Base Images
Before downloading the image from the image repository, let’s first review the current Docker base images that you currently have on your local system. To do so, run a PowerShell console as Administrator and then type docker images
. This command returns all images on your local system.
As you can see below, the images available are initially empty.
Downloading the Base Image
Now it’s time to download the base IIS image from Docker Hub. To do so, run docker pull
as shown below. This process can take some time to complete depending on your internet speeds.
PS51> docker pull mcr.microsoft.com/windows/servercore/iis
Now run docker images
and you should have the latest Microsoft Windows Core IIS image available for this tutorial.
Inspecting the Dockerfile
In an earlier step, you had downloaded an existing Dockerfile for this tutorial. Let’s now take a look at exactly what that entails.
Open the C:ContainersContainer1Dockerfile file in your favorite editor. The contents of this Dockerfile are used to define how the container image will be configured at build time.
You can see an explanation of what each piece of this file does in the in-line comments.
# Specifies that the latest microsoft/iis image will be used as the base image
# Used to specify which base container image will be used by the build process.
# Notice that the naming convention is "**owner/application name : tag name**"
# (shown as microsoft/iis:latest); so in our case the owner of the image is
# Microsoft and the application is IIS with the "latest" tag name being used
# to specify that you will pull the most recent image version available.
FROM microsoft/iis:latest
# Copies contents of the wwwroot folder to the inetpub/wwwroot folder in the new container image
# Used to specify that you want to copy the WWWroot folder to the IIS inetpub WWWroot
# folder in the container. You don't have to specify the full path to your local
# files because docker already has the logic built-in to reference files and folders
# relative to the docker file location on your system. Also, make note that that
# docker will only recognize forward slashes for file paths - since this is a
# Windows based container instead of Linux.
COPY wwwroot c:/inetpub/wwwroot
# Run some PowerShell commands within the new container to set up the image
# Run the PowerShell commands to remove the default IIS files and create a new
# application pool called TestPool
RUN powershell Remove-Item c:/inetpub/wwwroot/iisstart.htm -force
RUN powershell Remove-Item c:/inetpub/wwwroot/iisstart.png -force
RUN powershell Import-Module WebAdministration
RUN powershell New-WebAppPool -Name 'TestPool'
# Exposes port 80 on the new container image
# Used to open TCP port 80 for allowing an http connection to the website.
# However, this line is commented out, because the IIS container has this port
# already open by default.
#EXPOSE 80
# Sets the main command of the container image
# This tells the image to run a service monitor for the w3svc service.
# When this is specified the container will automatically stop running
# if the w3svc service stopped. This line is commented out because of the
# IIS container already has this entrypoint in place by default.
#ENTRYPOINT ["C:\ServiceMonitor.exe", "w3svc"]
Building a New Docker Image
You’ve got the Dockerfile ready to go and a base IIS image downloaded. Now it’s time to build your new Docker image using the Dockerfile.
To build a new image, use the docker build "tag"
command. This command creates the image. For this article, you can see below you’re also using the -t **
option which replaces the “tag” portion. This option allows you to give your new image a friendly tag name and also reference the Dockerfile by specifying the folder path where it resides.
Below you can see an example of ensuring the console is in the C:Containers directory and then building a new image from the Dockerfile in the C:ContainersContainer1 directory.
PS51> cd C:Containers
PS51> docker build -t container1 .Container1
Once started, you can see the progress of the command as it traverses each instruction in the docker file line by line:
Once done, you should now have a new Docker image!
Now run the docker images
command to view the images that are available. You can see below an example of the container1 image created.
Note: The
docker build —help
command is a useful parameter to display detailed information on the docker command being run.
Running the Docker Container
At this point, you should have a new image created. It’s time to spin up a container using that image. To bring up a new container, use the docker run
command.
The docker run
command will bring up a new Docker container based on the container1 image that you created earlier. You can see an example of this below.
Notice that the -d
parameter is used. This tells the docker runtime to start the image in the detached mode and then exit when the root process used to run the container exits.
When docker run
completes, it returns the ID of the container created. The example below is capturing this ID into a $containerID
variable so we can easily reference it later.
PS51> $containerID = docker run -d container1
PS51> $containerID
Once the container is brought up, now run the docker ps
command. This command allows you to see which containers are currently running using each image. Notice below that the running image is automatically generated a nickname (busy_habit in this case). This nickname is sometimes used instead of the container ID to manage the container.
Running Code Inside a Docker Container
A new container is built from a new image you just created. Let’s now start actually using that container to run code. Running code inside of a Docker container is done using the docker exec
command.
In this example, run docker exec
to view PowerShell output for the Get-ChildItem
command in the container using the command syntax below. This will ensure the instructions in the Dockerfile to remove the default IIS files succeeded.
PS51> docker exec $containerID powershell Get-ChildItem c:inetpubwwwroot
You can see below that the only file that exists is index.html which means the default files were removed.
Now run the ipconfig
command in the container to get the local IP address of the container image so that you can try to connect to the IIS website.
PS51> docker exec $containerID ipconfig
You can see below that ipconfig
was run in the container just as if running on your local computer and has return all of the IP information.
ipconfig
in a Docker containerInspecting the IIS Website
Now it’s time to reveal the fruits of your labor! It’s time to see if the IIS server running in the Docker container is properly serving up the index.html page.
Open a browser and paste the IP4 Address found via ipconfig
into the address bar. If all is well, you should see a Hello World!! message like below.
Reviewing Docker History
One useful command to use when working with Docker containers i the docker history
command. Although not necessarily related to creating an image or container itself, the docker history
command is a useful command that allows you to review changes made to the container image.
PS51> docker history container1
You can see below, that docker history
returns all of the Dockerfile and PowerShell activity performed on the container1 container you’ve been working with.
docker history
Cleaning up the Running Docker Images
The steps below are used to cleanup all stopped containers running on your machine. This will free up diskspace and system resources.
Run the docker ps
command to view a list of the containers running on your system:
Now stop the running containers using the docker stop
command:
PS51> docker stop <image nick name: busy_haibt in my case>
PS51> docker stop <image nick name: unruffled_driscoll in my case>
Finally you can permanently remove the stopped containers using the docker system prune
command.
PS51> docker system prune
Further Reading
- Creating Your First Docker Windows Server Container
- How to Manage Docker Volumes on Windows
Windows Images
This repository contains build instructions and Dockerfile to build Docker images with Windows-only browsers: Internet Explorer
and Microsoft Edge
.
System Requirements
- Bare metal machine or on VM with nested virtualization enabled and Linux installed. This example was tested on
Ubuntu 18.04
.
$ uname -a
Linux desktop 4.15.0-46-generic #49-Ubuntu SMP Wed Feb 6 09:33:07 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
To check that virtualization is supported — verify that /dev/kvm
file is present:
$ ls -l /dev/kvm
crw-rw---- 1 root kvm 10, 232 мар 8 19:38 /dev/kvm
- Qemu machine emulator installed. It is important to use the same
qemu
version on host machine where images are built and inside Docker image. To checkqemu
version type:
$ qemu-system-x86_64 -version
QEMU emulator version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.10)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers
- Windows license key
Build Procedure
1. Preparative Steps
1.1) Clone this repository and change dir to it:
$ git clone https://github.com/aerokube/windows-images.git
$ cd windows-images
1.2) Download Windows 10 installation image from Microsoft Software Download website.
1.3) Download virtio drivers virtio-win-0.1.141.iso. In the next steps we assume that you now have two files in current directory:
$ ls
virtio-win-0.1.141.iso Win10_1809Oct_English_x32.iso
2. Windows Installation
2.1) Create hard disk image where Windows will be installed:
$ qemu-img create -f qcow2 hdd.img 40G
2.2) Run virtual machine and begin installation:
$ sudo qemu-system-x86_64 -enable-kvm
-machine q35 -smp sockets=1,cores=1,threads=2 -m 2048
-usb -device usb-kbd -device usb-tablet -rtc base=localtime
-net nic,model=virtio -net user,hostfwd=tcp::4444-:4444
-drive file=hdd.img,media=disk,if=virtio
-drive file=Win10_1809Oct_English_x32.iso,media=cdrom
-drive file=virtio-win-0.1.141.iso,media=cdrom
2.3) Windows will boot from installation image. Install Windows.
2.3.1) Proceed to the next step:
2.3.2) Click Install now:
2.3.3) Enter license key:
2.3.4) Choose Windows edition:
2.3.5) Read and accept license agreement:
2.3.6) Choose custom installation type:
2.3.7) Now you have to install virtio storage driver. Click Load driver:
2.3.8) Point to E:viostorw10x86
directory:
2.3.9) Click next to install driver:
2.3.10) Choose installation partition and click next:
2.3.11) Wait while installation finishes:
2.3.12) Setup user and password:
2.3.13) Do other post-install configuration steps until you get Windows installed:
2.3.14) Install Ethernet virtio driver. Open device manager and click Update driver:
Choose virtio cdrom and click OK:
Install driver:
Connect to network:
2.3.15) Disable Windows Firewall or add firewall rule to allow access to port 4444. This is needed to access webdriver binary port with Selenium test.
2.3.16) Configure Windows as you wish: install updates, change screen resolution, apply registry modifications and so on.
3. Adding WebDriver Binaries
These binaries will handle Selenium test requests and launch respective browser.
-
For Internet Explorer — download an archive with driver binary from Selenium official website, unpack it and put the binary to
C:WindowsSystem32
directory. -
For Microsoft Edge web driver binary can be installed with the following command:
> DISM.exe /Online /Add-Capability /CapabilityName:Microsoft.WebDriver~~~~0.0.1.0
4. Creating Quick Boot Memory Snapshot
This snapshot contains memory state and is needed to quickly restore virtual machine instead of doing full boot which is slow. To create it:
4.1) Shutdown virtual machine.
4.2) Create overlay image that will contain VM state:
$ qemu-img create -b hdd.img -f qcow2 snapshot.img
4.3) Run VM using snapshot.img as filesystem:
$ sudo qemu-system-x86_64 -enable-kvm
-machine q35 -smp sockets=1,cores=1,threads=2 -m 2048
-usb -device usb-kbd -device usb-tablet -rtc base=localtime
-net nic,model=virtio -net user,hostfwd=tcp::4444-:4444
-drive file=snapshot.img,media=disk,if=virtio
-monitor stdio
Please note that qemu
runs with monitor connected to stdio.
4.4) Browser configuration (required only for Internet Explorer).
Open Internet Explorer. The first time this browser is launched, it asks for the security setup. The option «Don’t use recommended settings» need to be selected as follows:
Then, the Internet Options have to be changed. These options can be opened using the configuration button located at the top of Internet Explorer. In the tab «Security», the protect mode for the zones «Internet» and «Restricted sites» have to be disabled, as shown in the following picture:
At this point, you have to close Internet Explorer. Select the option «Always close all tabs» when Internet Explorer is closing. Finally, you have to open again Internet Explorer and double check that the protected mode is turned off (it can be seen in a message box at the bottom of the browser).
4.5) Run web driver binary command.
- For Microsoft Edge — open command prompt with administrator privileges and run:
> MicrosoftWebDriver.exe --host=10.0.2.15 --port=4444 --verbose
- For Internet Explorer — open command prompt as unprivileged user and run:
> C:WindowsSystem32IEDriverServer.exe --host=0.0.0.0 --port=4444 --log-level=DEBUG
4.6) Minimize command line prompt window when driver is up and running.
4.7) Switch to terminal where qemu runs and type at qemu prompt:
Then type quit to stop VM:
To start VM from snapshot manually use the following command:
$ sudo qemu-system-x86_64 -enable-kvm
-machine q35 -smp sockets=1,cores=1,threads=2 -m 2048
-usb -device usb-kbd -device usb-tablet -rtc base=localtime
-net nic,model=virtio -net user,hostfwd=tcp::4444-:4444
-drive file=snapshot.img,media=disk,if=virtio
-loadvm windows
The command above is used in Dockerfile
entry point script.
5. Build Docker Image
5.1) Move filesystem and state files to image
directory in this repository:
$ mv hdd.img snapshot.img image
$ cd image
5.2) Build Docker image using provided Dockerfile:
$ docker build -t windows/edge:18 . # For Microsoft Edge
For Internet Explorer use:
$ docker build -t windows/ie:11 . # For Internet Explorer
5.3) Run a container from image:
$ docker run -it --rm --privileged -p 4444:4444 -p 5900:5900 windows/edge:18 # For Microsoft Edge
$ docker run -it --rm --privileged -p 4444:4444 -p 5900:5900 windows/ie:11 # For Internet Explorer
5.4) To see Windows screen inside running container — connect to vnc://localhost:5900
using selenoid as password.
5.5) To run Selenium tests — use http://localhost:4444
as Selenium URL.
Building your first docker image for Windows
Mar 29, 2019
• 4 min read
In this tutorial, I will demonstrate how to host a ASP.NET Core 2.2 application on Windows Containers by using a Docker image. A Docker image will be packaged with a ASP.NET Core application that will be ran when a container in spun up.
Before we get started with creating Docker image. Let’s make sure we have prerequisites done.
Prerequisites
- Installing docker-cli and other components to get started
- Visual Studio code.
- Docker extension for visual studio code.
Once you have the prerequisites, we will use publicly available ASP.NET Core
base image from Microsoft. Microsoft maintains their Docker images on Docker hub. Docker hub is a container registry to manage your Docker images either by exposing the image publicly or maintain it privately. Private image responsibilities cost money. Visit Docker Hub website to learn more about image repository management.
Building your first Docker Image
-
Open PowerShell console as an administrator
-
Let’s get started by pulling ASP.NET Core 2.2 docker image from Docker hub by executing below command.
docker pull mcr.microsoft.com/dotnet/core/aspnet:2.2
Your output should look similar to what is shown below:
-
Create a folder with your preference name whereever you prefer. I will use c:docker for demonstration purpose.
mkdir c:docker
-
Download
ASP.NET Core
application package from this URL.Invoke-WebRequest -UseBasicParsing -OutFile c:dockerWebAppCore2.2.zip https://github.com/rahilmaknojia/WebAppCore2.2/archive/master.zip
What we are doing in above command is downloading packaged code that is already build to save time on building a package.
-
Extract
WebAppCore2.2.zip
by using PowerShell 5.0 native command. If you do not have PowerShell 5.0 and above, you will have to manually extract the package.Expand-Archive c:dockerWebAppCore2.2.zip -DestinationPath c:docker -Force
-
Now let’s create a Docker file in c:docker folder.
New-Item -Path C:dockerDockerfile -ItemType File
-
Go ahead and open C:docker folder path in Visual Studio Code.
-
Now we will open
Dockerfile
by double clicking on the file in Visual Studio Code to start writing required steps to build an image.Copy and paste below code to
Dockerfile
.# Pull base image from Docker hub FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 # Create working directory RUN mkdir C:\app # Set a working directory WORKDIR c:\app # Copy package from your machine to the image. Also known as staging a package COPY WebAppCore2.2-master/Package/* c:/app/ # Run the application ENTRYPOINT ["dotnet", "WebAppCore2.2.dll"]
What we told the
Dockerfile
is to pull a asp.net core base image from Docker hub . Then we ran a command to create a directory calledapp
inc:app
path. We also told the container to setc:app
as a working directory. That way we can access binary directly when the container is spun up. We also added a step to copy all the binaries fromc:dockerWebAppCore2.2-masterPackage
to destination path in containerc:app
. Once we had package staged in container, we told it to run the application by executingdotnet WebAppCore2.2.dll
so that the app would be accessible from outside the container. To learn more aboutDockerfile
for windows, check out this microsoft documentation.Now that you have required steps to build an image, lets go ahead with below steps.
-
Navigate to
Dockerfile
working directory from PowerShell console. If you are already in that path you can ignore it.cd c:docker
-
Execute below command to build container image.
docker build -t demo/webappcore:2.2.0
What above command will do is create a docker image under
demo
path. With the image name called aswebappcore
and version 2.2.0.Your output should look like below once it is successful:
PS C:docker> docker build -t demo/webappcore:2.2.0 . Sending build context to Docker daemon 9.853MB Step 1/5 : FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 ---> 36e5a01ef28f Step 2/5 : RUN mkdir C:\app ---> Using cache ---> 8f88e30dcdd0 Step 3/5 : WORKDIR c:\app ---> Using cache ---> 829e48e68bda Step 4/5 : COPY WebAppCore2.2-master/Package/* c:/app/ ---> Using cache ---> 6bfd9ae4b731 Step 5/5 : ENTRYPOINT ["dotnet", "WebAppCore2.2.dll"] ---> Running in 4b5488d5ea5f Removing intermediate container 4b5488d5ea5f ---> 9729270fe1ac Successfully built 9729270fe1ac Successfully tagged demo/webappcore:2.2.0
-
Once the image has been built, you are now ready run the container. Execute below command.
docker run --name webappcore --rm -it -p 8000:80 demo/webappcore:2.2.0
The above command will create new container called as webappcore
with parameters.
--rm
is used to automatically remove the container after it is shutdown.-it
will open a session into your container and output all the logs.-p
is used for creating external port and assigning it to internal port of a container. Port 8000 is exposed to outside container, and port 80 is used to access the app within the container.demo/webappcore:2.2.0
is the path to the docker image to run as a container.
Output of a running container
- Browsing your application from your local machine
localhost:8000
.
This is it! You ran your first docker container in your local environment. Thank you for following the tutorial. Please comment below for any issue or feedback you would like to share.
Docker containers become unavoidable for infrastructure development as it provides, Isolation, Simplicity, Rapid Continuous Deployment, and Faster Configuration with Security. Earlier, Docker has only used for Linux based applications as it is using the Linux kernel baseline for creating Containers. But Windows applications are widely used in Software development and Hence, windows developers need Docker Containers for Windows. In this article, we will discuss How to Create Docker Windows Containers from Docker Desktop.
Docker Desktop Installation
Requirement
- Minimum Windows 10 (Home and All other Editions)
- Hyper-V (In-Built and can be Enabled)
- Only 64bit Processor Architecture
- Virtualization Enablement from Bios Level
Installation
- Step-1: Download the “Docker Desktop for Windows” exe file from here (https://hub.docker.com/editions/community/docker-ce-desktop-windows/) and run it to install.
- Step-2: Enable Docker Running Environment 1. For Windows Home – Enable Windows Subsystem for Linux (Instructions Here: https://docs.microsoft.com/en-us/windows/wsl/install-win10). 2. For Windows Other Editions – Enable Hyper-V (Instructions Here: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v)
- Step-3: Follow the instructions on the Installation process
- Step-4: If you are the Only user with Admin access, you can proceed. Else add the current user into a docker-users group (Instructions Here: https://www.tenforums.com/tutorials/88049-add-remove-users-groups-windows-10-a.html)
NOTE:
Docker Desktop Installed in the Windows Machine can run Linux Based Docker Containers and Windows-based Docker Container. But You cannot run Windows Based Docker Containers on Docker Engine installed in Linux. Refer the below image.
About Docker on Windows Machine
As we all know, the Docker Engine will run as a daemon that uses the Linux specific kernel features. So, running the Docker Engine on Windows directly is not possible. Hence, we must create a Linux based environment in Windows to run docker. In order to enable Linux environment on the windows, we have two options,
- Windows Subsystem for Linux (WSL) – is the compatibility layer to run Linux applications
- Hyper-V – Microsoft solution for virtualization.
Both these features are available from Windows 10. Running docker on windows will be ultimately using the Linux environment. But it is using some of the Host’s features. So, Docker Engine will sit on top of the Linux Kernel created by the Hyper-V/WSL. On top of the Docker Engine, Docker Containers can be created. All this is managed by the Docker Desktop. So, Application Program which will be written by the developers will sit on top of the Containers.
Simple Windows Container with Example
Let’s learn how to create the Docker Windows container using Docker Desktop. For that, first, we are going to create Dockerfile which is the simple text file with the instructions of the application and configurations.
Creating Dockerfile
Let’s run a simple application which will return the “hello world
” print output from the Windows Docker Container. For the same, create a file called “Dockerfile
” and put the bellow content.
# Base Image FROM microsoft/nanoserver # Copy powershell init-script from the host machine (windows) to the docker container. COPY init-setup.ps1 c:\workspaceapplicationinit-setup.ps1 # Run the Powershell script in the Docker Container CMD ["powershell.exe", "c:\workspaceapplicationinit-setup.ps1"]
- In this, Line number #2 is setting the container from the base image. Here it is “
microsoft/nanoserver”.
- Inline Number #5 is giving
init-script.ps1
from the host to the docker container. - Line Number #8 is to run the script in PowerShell executable.
And Create a script file called “init-setup.ps1
” and put the below content inside the file
Building Docker Image
Once you have this file in your folder you can start building the Dockerfile as Docker image using the command.
$ docker build -t digitalvarys/print-hello-world .
where digitalvarys/print-hello-world
is the tag name of the docker image.
Once the Docker image is been built, you can check the Image by passing the following commad
This will display the created image.
Running the Docker Container
Now, it is time to run the Docker image which we have created. Hence, run the following command
$ docker run digitalvarys/print-hello-world
This will print the string “hello world
” as we provided.
If you run it with -it
parameter, you can explore the Created Docker Container with Windows CMD.
ASP.net example of the Windows Docker Container.
The above sample application will tell you about the basic container feature. This one will tell you the real-time advantage of the Windows Docker Container.
Sample application
For this tutorial, we are going to use, cloud foundry’s sample Dotnet core hello world application (https://github.com/cloudfoundry-samples/dotnet-core-hello-world). Just clone it and keep it in your working directory
Dockerfile creation.
Now, we are going to create Dockerfile to create the image of the above application.
# Base Image FROM microsoft/dotnet:nanoserver-core # Copy entire application code folder dotnet-application to the working directory in Container. COPY c:\workspacedotnet-application . # Relax the firewall rule to expose port 5000 EXPOSE 5000 # Run the dotnet application CMD ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"]
Just like the PowerShell example, we are going to take the base image and copy the application from the host to the container. Then, we are going to expose the port 5000 to run the dotnet application in this port. Then, we are going to run the application using the dotnet executable.
Building the Docker Image.
Once the Dockerfile is ready, we have to build the Docker container.
$ docker build -t digitalvarys/simple-dotnet-application .
Here, I am giving the image name as “digitalvarys/simple-dotnet-application
”.
Running the Docker Container
Now, we have to run the application in background (detached mode),
$ docker run -d -p 5000:5000 digitalvarys/simple-dotnet-application
This will run the container and expose the container port to the host port 5000.
Getting the IP address of the Created Docker Container.
Now, Just inspect the Docker container and see the assigned IP address of the running container,
$ docker inspect [container-id]
This will show you the JSON response. In that, check for “networks
” -> “nat
” -> “IPAddress
”. This will be your container IP address.
Now, Just enter the URL in the browser as https://[container-ip-address]:5000, then you will see the Hello world
message in the browser. This means your application is running in a container.
Conclusion
As we already discussed, Docker is unavoidable for the application development or at least in the process of application development. But the Containerization of the Windows application like dotnet application needs extra lookup. Hope this article covers enough concepts and procedures for the Windows Docker Containers running on windows application. In our upcoming article, we will discuss more running a cluster of Microsoft Windows-based applications in Docker Swarm and Kubernetes. Stay tuned and subscribe DigitalVarys for more articles and study materials on DevOps, Agile, DevSecOps and App Development.
Experienced DevSecOps Practitioner, Tech Blogger, Expertise in Designing Solutions in Public and Private Cloud. Opensource Community Contributor.
Добро пожаловать в гайд по изучению Docker, в котором я проиллюстрирую вам совершенно иной подход при разработке ваших приложений с его помощью. Эту статью вы можете считать как быстрый старт, введение в Docker.
Когда вы полностью прочитаете эту статью, уверен, вы поймёте, что такое Docker, для чего нужен, и где используется.
Но основным ключом к его освоению — это полное повторение процесса написания кода, как демонстрируется в этой статье. Это гайд по работе с Docker для новичков, потому, повторение процесса у себя на компьютере — обязательное условие к его пониманию. Одного чтения недостаточно, важно — повторение процесса и много практики. Так же чтобы наконец-то научиться работать с ним, даже при условии плохого понимая Docker-а, начните его уже применять в своей разработке. Начните, и увидите, как стали продвинутым его пользователем.
Когда я наконец-то понял все тонкости работы с Docker (на полное изучение которого ушло несколько месяцев), и начал правильно применять его при разработке (а он как раз и нужен для разработки, в большей степени), то почувствовал, как будто обрёл какую-то сверхспособоность. Смотря на свой опыт изучения Докера, я понял, что мне есть что рассказать, и чем поделиться. В этой статье я постарался создать максимально понятную для новичков инструкцию, благодаря которой вы сможете полностью изучить Docker за 30 минут. Я долго думал о том, чтобы написать туториал, и наконец-то осилил эту задачу, и, как мне кажется, получилось неплохо
Эта инструкция так же подходит для тех, кто не имеет никаких знаний, или опыта работы с докером, или аналогичным программным обеспечением. Вы получите все важные знания, необходимые для работы. Статья построена по принципу от простого к сложному. В итоге статьи вы будете чётко понимать, что такое Docker, зачем нужен, как с ним работать, и применять его для разработки: создавать окружение, необходимое для создания вашего приложения.
Эта статья, в больше мере, нацелена на получение практических знаний, и только немного теории, построенной на аналогиях из жизни. Потому, эта статья имеет окрас веселья и лайтовости, в большей мере, чем супер-конкретики и теоретических нюансов.
В этом туториале я показываю всё на примере ОС Windows 10, делая все команды из консоли винды, и демонстрируя процесс установки Docker на Windows 10. Но, все команды будут работать аналогично и на Linux и Mac. Эта статья — это продолжение ряда статей, посвященных настройке рабочего окружения. В прошлой статье мы рассматривали работу с Vagrant, что не менее интересно, чем Docker. И Docker и Vagrant преследуют цель — упростить жизнь разработчикам, но с Докером открывается больше возможностей.
Так же, прошу заметить, если вы используете Vagrant, и решите установить Docker, то Vagrant перестанет работать. Такая жизнь, но с этим можно смириться, тем более, субъективно, Docker круче ^^.
Что вы узнаете из этой статьи
- Как работает Docker?
- Как установить Docker на Windows?
- Что такое Docker Image (образ)?
- Что такое Docker контейнер?
- Что такое Docker Volumes?
- Что такое Dockerfile?
- Как пробрасывать локальную папку в контейнер Докера (монтирование папки)?
- Как работают и пробрасываются Docker порты?
- Слои Docker образа, особенности создания образов.
- Что такое Docker-compose?
- Что такое микросервисы и микросервисная архитектура?
Что такое Docker
О том, как появился Docker:
Docker — это программное обеспечение, которое начинало с того, что зародилось в одной компании, как внутренний проект platform-as-a-service
в компании dotCloud.
В процессе развития Докера, он вырос из масштабов внутреннего проекта, стал доступен для широких масс, и затмил своей популярностью своего родителя dotCloud
, из-за чего было принято решение создать новую отдельную компанию под названием Docker Incorporated. Направление новосозданной компании было только в разработке Докера, и развитию его экосистемы.
На сайте Докера можно найти статью, в которой подробно рассказывается, что такое Docker. Из их слов — это стандартизированное ПО для разработки и развёртывания проектов.
Но, что это на самом деле значит?
Давайте на секунду забудем про Докер, и вспомним про такую ностальгическую штуку, как GameBoy Color
:
Если вы помните, игры для этой приставки поставлялись в виде картриджей:
И я уверен в том, что производители видео игр пользуются успехом из-за своей простоты:
- Когда ты хочешь поиграть, ты просто вставляешь картридж в приставку, и игра сразу же работает.
- Ты можешь поделиться своей игрой с друзьями, передав всего лишь картридж, который они вставят в приставку, и сразу же смогут играть.
Docker следует похожему принципу — позволяет запускать своё ПО настолько просто, что это соизмеримо с вставкой картриджа и нажатием кнопки ON на приставке.
Это основная суть, почему Docker настолько полезен — теперь кто угодно, у кого установлен Docker может запустить ваше приложение, выполнив для этого всего несколько команд.
Раньше, вы, создавая приложения, к примеру на PHP, устанавливали локально PHP, MySql, возможно, NodeJs, при этом устанавливая зависимости в виде нужных расширений и библиотек. И, в случае передачи вашего скрипта какому-то знакомому, ему требовалось настраивать аналогичное окружение, аналогичных версий, иметь аналогичные расширения и конфигурацию, чтобы успешно запустить ваше приложение.
Сейчас же, при использовании Докера, такой проблемы не возникнет впринципе. Теперь вам достаточно иметь установленную программу Docker, которая по одной вашей команде установит окружение, описанное в конфиге для запуска вашего приложения.
Какое программное обеспечение можно запустить с помощью докера? В техническом плане, Docker чем-то похож на виртуальную машину:
Докер — это движок, который запускает виртуальную операционную систему, имеющую чрезвычайно маленький вес (в отличие от Vagrant-а, который создаёт полноценную виртуальную ОС, Докер, имеет особые образы ПО, запускающиеся в виртуальной среде, не создавая полную копию ОС).
Docker позволяет запустить ОС Linux в изолированной среде очень быстро, в течение нескольких минут.
Зачем использовать Docker?
Кошмар при установке ПО, с которым приходится сталкиваться. У вас когда-нибудь было такое, что вы пытаетесь установить ПО на ваш компьютер, а оно отказывается работать? Вы получаете несколько непонятных вам ошибок, из-за которых ничего не запускается. И после нескольких часов гугления, на десятой странице гугла…и на каком-то форуме, до этого неизвестного вам, вы наконец-то находите случайный комментарий, который помогает исправить вашу проблему.
Аналогично, что делает написание PC игр более сложным, чем написание Game Boy игр — это то, что приходится проектировать систему с учётом большого множества существующих PC девайсов и спецификаций. Так как разные компьютеры имеют различные операционные системы, драйвера, процессоры, графические карты, и т.д.
И потому задача разработчика — написать приложение совместимое со всеми популярными системами, является достаточно затруднительной и трудоёмкой.
Docker спасёт нас. Docker, как и Game Boy приставка, берёт стандартизированные части программного обеспечения и запускает их так, как Game Boy запускал бы игру.
В этом случае вы не должны беспокоиться об операционной системе, на которой пользователь будет запускать ваше приложение. Теперь, когда пользователи будут запускать приложение через Docker — конфигурация будет собрана автоматически, и код будет выполняться ВСЕГДА.
Как разработчик, теперь вы не должны волноваться о том, на какой системе будет запущено ваше приложение.
Как пользователь, вам не нужно волноваться о том, что вы скачаете неподходящую версию ПО (нужного для работы программы). В Докере эта программа будет запущена в аналогичных условиях, при которых это приложение было разработано, потому, исключается факт получить какую-то новую, непредвиденную ошибку.
Для пользователя все действия сводятся к принципу подключи и играй.
Установка Docker
Docker доступен для любой из операционных систем: Windows, Linux, Max
. Для скачивания установочного файла — перейдите по ссылке и выберите подходящую вам версию. Я же, как и писал ранее, выбираю версию docker для Windows 10
.
Docker предоставляет 2 сборки:
- Community Edition (полностью бесплатная версия)
- Enterprise Edition (платно). Enterprise Edition содержит в себе дополнительные
свистелки-перделкифункции, которые, на данном этапе, точно не нужны. Функциональность, которую мы будем использовать совершенно не отличается в этих двух сборках.
После установки потребуется перезагрузка системы, и уже можно начинать полноценно работать с Докером.
Для того, чтобы проверить, запущен ли Docker
, откроем командную строку (на Windows 10
— Нажмите кнопку windows, и начните писать командная строка)
Где, напишем команду docker
, и в случае успешно работающего докера, получим ответ
Дальше, нужно удостовериться, что вместе с докером, доступен так же, docker-compose
, для этого, выполним команду:
docker-compose
(вывод обеих команд будет примерно одинакового содержания).
Если вы используете Linux, то, docker-compose нужно будет устанавливать отдельно по инструкции.
Что такое Docker Image?
Docker образ (он же Docker Image), похож на Game Boy картридж — это просто программное обеспечение. Это стандартизированное программное обеспечение, которое запускается на любой приставке Game Boy. Вы можете дать игру вашему другу, и он сможет просто вставить картридж в приставку, и играть.
Как в случае с картриджами, бывают различные игры, так и Docker имеет различные образы ПО: ubuntu
, php
(который наследуется от оригинального образа Ubuntu), nodejs
, и т.д.
Рассмотрим пример скачивания нашего первого образа.
Для этого, существует команда:
docker pull <IMAGE_NAME>
, где <IMAGE_NAME>
— имя скачиваемого образа
Зная эту команду, скачаем образ Ubuntu 18.10
:
docker pull ubuntu:18.10
Эта команда сообщает Докеру о том, что нужно скачать образ Ubuntu 18.10
с Dockerhub.com — основной репозиторий Docker-образов, на котором вы и можете посмотреть весь их список и подобрать нужный образ для вашей программы.
Это как поездка за новым картриджем в магазин, только намного быстрее :).
Теперь, для того, чтобы посмотреть список всех загруженных образов, нужно выполнить:
docker images
У вас, как и на скрине, должен появиться только что скачанный образ Ubuntu 18.10
.
Как и обсуждалось выше, по поводу маленького размера образов, чистый образ Ubuntu при установке из Docker-образа, весит всего 74 МБ
. Не чудо ли?
Проводя аналогии, команда docker images
выглядит как коллекция картриджей от приставки, которые у вас есть сейчас:
Что такое Docker контейнер?
Теперь представьте, что мы обновили нашу приставку с Game Boy
на GameCube
. Игры хранятся на диске, который предназначен только для чтения самого образа игры. А прочие файлы (сохранения, кеш и т.д.) сохраняются внутри самой приставки, локально.
Так же, как и игра на диске, исходный Docker Image (образ) — неизменяемый.
Docker контейнер — это экземпляр запущенного образа. Аналогично тому, что вы вставляете диск в приставку, после чего игра начинается.
А сам образ игры никак не модифицируется, все файлы, содержащие изменения хранятся где-то локально на приставке.
Запуск Docker контейнера соответствует тому, что вы играете в свою Gamecube игру. Docker запускает ваш образ в своей среде, аналогично тому, как Gamecube запускает игру с диска, не модифицируя оригинальный образ, а лишь сохраняя изменения и весь прогресс в какой-то песочнице.
Для запуска контейнера существует команда:
docker run <image> <опциональная команды, которая выполнится внутри контейнера>
Давайте запустим наш первый контейнер Ubuntu:
docker run ubuntu:18.10 echo 'hello from ubuntu'
Команда echo 'hello from ubuntu'
была выполнена внутри среды Ubuntu. Другими словами, эта команда была выполнена в контейнере ubuntu:18.10.
Теперь выполним команду для проверки списка запущенных контейнеров:
docker ps
Здесь пустота… это потому что docker ps
показывает только список контейнеров, которые запущены в данный момент (наш же контейнер выполнил одну команду echo 'hello from ubuntu'
и завершил свою работу).
А для того, чтобы посмотреть список всех контейнеров без исключения, нужно добавить флаг -a
, выполним:
docker ps -a
После выполнения нужных операций внутри контейнера, то Docker-контейнер завершает работу. Это похоже на режим сохранения энергии в новых игровых консолях — если вы не совершаете действий какое-то время, то система выключается автоматически.
Каждый раз, когда вы будете выполнять команду docker run
, будет создаваться новый контейнер, на каждую из выполненных команд.
Выполнение неограниченное количество команда внутри контейнера
Давайте добавим немного интерактивности в наше обучение. Мы можем подключиться к консоли виртуальной ОС (Ubuntu 18.10
), и выполнять любое количество команд без завершения работы контейнера, для этого, запустим команду:
docker run -it ubuntu:18.10 /bin/bash
Опция -it
вместе с /bin/bash
даёт доступ к выполнению команд в терминале внутри контейнера Ubuntu.
Теперь, внутри этого контейнера можно выполнять любые команды, применимые к Ubuntu
. Вы же можете представлять это как мини виртуальную машину, условно, к консоли которой мы подключились по SSH.
В результате, теперь мы знаем возможные способы, как подключиться к контейнеру, и как выполнить команду в контейнере Docker-а.
Узнаём ID контейнера
Иногда является очень полезным узнать ID контейнера, с которым мы работаем. И как раз-таки, при выполнении команды docker run -it <IMAGE> /bin/bash
, мы окажемся в терминале, где все команды будут выполняться от имени пользователя root@<containerid>
.
Теперь, все команды буду выполняться внутри операционной системы Ubuntu
. Попробуем, например, выполнить команду ls
, и посмотрим, список директорий, внутри этого образа Ubuntu.
Docker контейнер является полностью независимым от системы хоста, из которой он запускался. Как изолированная виртуальная машина. И в ней вы можете производить любые изменения, которые никак не повлияют на основную операционную систему.
Это аналогично тому, как, если бы вы играли в Mario Kart
на приставке Gamecube
, и неважно, что вы делаете в игре, вы никак не сможете изменить само ядро игры, или изменить информацию, записанную на диске.
Контейнер является полностью независимым и изолированным от основной операционной системы, аналогично виртуальной операционной системе. Вы можете вносить любые изменения внутри виртуалки, и никакие из этих изменений не повлияют на основную операционную систему.
Теперь откройте новое окно терминала (не закрывая и не отключаясь от текущего), и выполните команду docker ps
Только на этот раз вы можете увидеть, что контейнер с Ubuntu 18.10
в текущий момент запущен.
Теперь вернёмся назад к первому окну терминала (который находится внутри контейнера), и выполним:
mkdir /truedir #создаст папку truedir
exit #выйдет из контейнера, и вернётся в основную ОС
Выполнив команду exit
, контейнер будет остановлен (чтобы убедиться, можете проверить командой docker ps
). Теперь, вы так же знаете, как выйти из Docker контейнера.
Теперь, попробуем ещё раз просмотреть список всех контейнеров, и убедимся, что новый контейнер был создан docker ps -a
Так же, для того, чтобы запустить ранее созданный контейнер, можно выполнить команду docker start <CONTAINER_ID>
,
где CONTAINER_ID — id контейнера, который можно посмотреть, выполнив команду docker ps -a
(и увидеть в столбце CONTAINER_ID)
В моём случае, CONTAINER_ID последнего контейнера = 7579c85c8b7e (у вас же, он будет отличаться)
Запустим контейнер командой:
docker start 7579c85c8b7e #ваш CONTAINER_ID
docker ps
docker exec -it 7579c85c8b7e /bin/bash #ваш CONTAINER_ID
И теперь, если внутри контейнера выполнить команду
ls
, то можно увидеть, что ранее созданная папка truedir существует в этом контейнере
Команда exec
позволяет выполнить команду внутри запущенного контейнера. В нашем случае, мы выполнили /bin/bash
, что позволило нам подключиться к терминалу внутри контейнера.
Для выхода, как обычно, выполним exit
.
Теперь остановим и удалим Docker контейнеры командами:
docker stop <CONTAINER_ID>
docker rm <CONTAINER_ID>
docker ps a # просмотрим список активных контейнеров
docker stop aa1463167766 # остановим активный контейнер
docker rm aa1463167766 # удалим контейнер
docker rm bb597feb7fbe # удалим второй контейнер
В основном, нам не нужно, чтобы в системе плодилось большое количество контейнеров. Потому, команду
docker run
очень часто запускают с дополнительным флагом —rm, который удаляет запущенный контейнер после работы:
docker run -it --rm ubuntu:18.10 /bin/bash
Что такое DockerFile?
Docker позволяет вам делиться с другими средой, в которой ваш код запускался и помогает в её простом воссоздании на других машинах.
Dockerfile — это обычный конфигурационный файл, описывающий пошаговое создание среды вашего приложения. В этом файле подробно описывается, какие команды будут выполнены, какие образы задействованы, и какие настройки будут применены. А движок Docker-а при запуске уже распарсит этот файл (именуемый как Dockerfile), и создаст из него соответствующий образ (Image), который был описан.
К примеру, если вы разрабатывали приложение на php7.2, и использовали ElasticSearch 9 версии, и сохранили это в Dockerfile-е, то другие пользователи, которые запустят образ используя ваш Dockerfile, получат ту же среду с php7.2 и ElasticSearch 9.
С Dockerfile вы сможете подробно описать инструкцию, по которой будет воссоздано конкретное состояние. И делается это довольно-таки просто и интуитивно понятно.
Представьте, что вы играете в покемонов
Вы пытаетесь пройти первый уровень, но безрезультатно. И я, как ваш друг, хочу с этим помочь. У меня есть 2 таблетки варианта:
- Я дам вам файл сохранений, в котором игра ничинается со второго уровня. Всё что вам нужно — это загрузить файл.
- Я могу написать инструкцию, в которой опишу шаг за шагом процесс прохождения уровня. Это как рецепт, которому нужно будет следовать в точности, как описано. Эта инструкция могла бы выглядеть как-то так:
Инструкция прохождения первого уровня
- Выбрать покемона Squirtle
- Направляйтесь к лесу, к северу от города
- Тренируйтесь, пока покемон не достигнет 10 уровня
- Направляйтесь в Оловянный город
- Подойдите к боссу, и победите его заклинанием Watergun
Что является более полезным? Я склоняюсь, что это второй вариант. Потому что он демонстрирует, как добиться желаемого состояния. Это не просто чёрный ящик, который переносит игру на второй уровень.
С докером вы так же имеете два варианта при создании образа:
- Вы можете запаковать ваш контейнер, создать из него образ (аналогично тому, что вы запишите на диск новую игру с собственными модификациями). Это похоже на способ, когда вы делитесь сохранениями напрямую.
- Или же, можно описать Dockerfile — подробную инструкцию, которая приведёт среду к нужному состоянию.
Я склоняюсь ко второму варианту, потому что он более подробный, гибкий, и редактируемый (вы можете переписать Dockerfile, но не можете перемотать состояние образа в случае прямых изменений).
Пришло время попрактиковаться на реальном примере. Для начала, создадим файл cli.php в корне проекта с содержимым:
<?php
$n = $i = 5;
while ($i--) {
echo str_repeat(' ', $i).str_repeat('* ', $n - $i)."n";
}
И файл под названием Dockerfile, с содержимым:
FROM php:7.2-cli
COPY cli.php /cli.php
RUN chmod +x /cli.php
CMD php /cli.php
Имена команд в Dockerfile (выделенные красным) — это синтаксис разметки Dockerfile. Эти команды означают:
- FROM — это как буд-то вы выбираете движок для вашей игры (Unity, Unreal, CryEngine). Хоть вы и могли бы начать писать движок с нуля, но больше смысла было бы в использовании готового. Можно было бы использовать, к примеру, ubuntu:18.10, в нашем коде используется образ php:7.2-cli, потому весь код будет запускаться внутри образа с предустановленным php 7.2-cli.
- COPY — Копирует файл с основной системы в контейнер (копируем файл cli.php внутрь контейнера, с одноимённым названием)
- RUN — Выполнение shell-команды из терминала контейнера (в текущем случае, присвоим права на выполнение скрипта /cli.php
- CMD — Выполняет эту команду каждый раз, при новом запуске контейнера
Для просмотра полного списка команд можете перейти по ссылке
При написании Dockerfile, начинать следует с наиболее актуального существующего образа, дополняя его в соответствии с потребностями вашего приложения.
К примеру, мы могли не использовать образ php:7.2-cli, а могли взять ubuntu:18.10, последовательно выполняя команды в RUN одна за одной, устанавливая нужное ПО. Однако, в этом мало смысла, когда уже есть готовые сборки.
Для создания образа из Dockerfile нужно выполнить:
docker build <DOCKERFILE_PATH> --tag <IMAGE_NAME>
<DOCKERFILE_PATH> — путь к файлу Dockerfile (.
— текущая директория),
<IMAGE_NAME> — имя, под которым образ будет создан
Выполним:
docker build . --tag pyramid
При том, что имя файла Dockerfile при указывании пути упускается, нужно указывать только директорию, в которой этот файл находится (а
.
означает, что файл находится в той директории, из которой была запущена консоль)
После того, как команда выполнилась, мы можем обращаться к образу по его имени, которое было указано в <IMAGE_NAME>, проверим список образов: docker images
Теперь, запустим контейнер из нашего образа командой docker run pyramid
Круто! Shell скрипт был успешно скопирован, и выполнен благодаря указанному в Dockerfile параметру CMD.
Сначала мы скопировали файл cli.php в Docker образ, который создался с помощью Dockerfile. Для того, чтобы удостовериться в том, что файл действительно был проброшен внутрь контейнера, можно выполнить команду docker run pyramid ls
, которая в списке файлов покажет и cli.php.
Однако, сейчас этот контейнер недостаточно гибкий. Нам бы хотелось, чтобы можно было удобно изменять количество строк, из скольки состоит пирамида.
Для этого, отредактируем файл cli.php, и изменим, чтобы количество аргументов принималось из командной строки. Отредактируем вторую строку на:
$n = $i = $argv[1] ?? 5; //а было $n = $i = 5
// это значит, что мы принимаем аргумент из консоли, а если он не получен, то используем по-умолчанию 5
После чего, пересоберём образ: docker build . --tag pyramid
И запустим контейнер: docker run pyramid php /cli.php 9
, получив вывод ёлки пирамиды в 9 строк
Почему это работает?
Когда контейнер запускается, вы можете переопределить команду записанную в Dockerfile в поле CMD.
Наша оригинальная CMD команда, записанная в Dockerfile php /cli.php
— будет переопределена новой php /cli.php 9
.
Но, было бы неплохо передавать этот аргумент самому контейнеру, вместо переписывания всей команды. Перепишем так, чтобы вместо команды php /cli.php 7
можно было передавать просто аргумент-число.
Для этого, дополним Dockerfile:
FROM php:7.2-cli
COPY cli.php /cli.php
RUN chmod +x /cli.php
ENTRYPOINT ["php", "/cli.php"]
## аргумент, который передаётся в командную строку
CMD ["9"]
Мы немного поменяли формат записи. В таком случае, CMD будет добавлена к тому, что выполнится в ENTRYPOINT.
["php", "/cli.php"]
на самом деле запускается, как php /cli.php
. И, учитывая то, что CMD будет добавлена после выполнения текущей, то итоговая команда будет выглядеть как: php /cli.php 9
— и пользователь сможет переопределить этот аргумент, передавая его в командную строку, во время запуска контейнера.
Теперь, заново пересоберём образ
docker build . --tag pyramid
И запустим контейнер с желаемым аргументом
docker run pyramid 3
Монтирование локальной директории в Docker-контейнер
Монтирование директории в Docker контейнер — это предоставление доступа контейнеру на чтение содержимого вашей папки из основной операционной системы. Помимо чтения из этой папки, так же, контейнер может её изменять, и такая связь является двусторонней: при изменении файлов в основной ОС изменения будут видны в контейнере, и наоборот.
Когда игра читает файлы сохранений, файловая система Game Cube внедряет их в текущий сеанс игры (представим это, даже если это не так). Игра может изменять файл сохранений, и это изменение отразится на файловой системе Game Cube, т.е. возникает двусторонняя связь.
Монтирование директории в контейнер позволяет ему читать и писать данные в эту директорию, изменяя её состояние.
Для того, чтобы смонтировать папку из основной системы в контейнер, можно воспользоваться командой
docker run -v <DIRECTORY>:<CONTAINER_DIRECTORY> ...
,
где DIRECTORY — это путь к папке, которую нужно смонтировать,
CONTAINER_DIRECTORY — путь внутри контейнера.
Только путь к монтируемой папке должен быть прописан полностью:
C:projectsdocker-example
, или на *nix-системах можно воспользоваться конструкцией$(pwd)
Выполним команду:
docker run -it -v C:projectsdocker-examplecli:/mounted ubuntu:18.10 /bin/bash
ls
ls mounted
touch mounted/testfile
При выполнении этой команды, указанная папка смонтируется в папку /mounted, внутри файловой системы контейнера, а команда touch mounted/testfile
создаст новый файл под названием testfile, который вы можете увидеть из основной ОС.
Теперь вы можете увидеть, что после выполнения этой команды в текущей директории появился новый файл testfile. И это говорит о том, что двусторонняя связь работает — при изменении директории на основной ОС всё отразится на смонтированную папку внутри контейнера, а при изменениях изнутри контейнера всё отразится на основную ОС.
Монтирование папки позволяет вам изменять файлы вашей основной системы прямо во время работы внутри Docker контейнера.
Это удобная особенность, которая позволяет нам редактировать код в редакторе на основной ОС, а изменения будут сразу же применяться внутри контейнера.
Что такое Docker Volumes?
Docker Volumes — что-то похоже на карты памяти для Game Cube. Эта карта памяти содержит данные для игры. Эти карты съемные, и могу работать, когда Gamecube приставка выключается. Вы так же можете подключить различные карты памяти, содержащие разные данные, а так же, подключать к разным приставкам.
Вы можете вставить вашу карту внутрь приставки, точно так же, как и Docker Volume может быть прикреплён к любому из контейнеров.
С Docker Volum-ами мы имеем контейнер, который хранит постоянные данные где-то на нашем компьютере (это актуально, потому что после завершения работы контейнер удаляет все пользовательские данные, не входящие в образ). Вы можете прикрепить Volume-данные к любому из запущенных контейнеров.
Вместо того, чтобы каждый раз, при запуске контейнера, писать, какие из папок вы хотите смонтировать, вы просто можете создать один контейнер с общими данными, который потом будете прикреплять.
Лично я, не использую это очень часто на практике, потому что есть много других методов по управлению данными. Однако, это может быть очень полезно для контейнеров, которые должны сохранять какие-то важные данные, или данные, которыми нужно поделиться между несколькими контейнерами.
Порты контейнеров
Docker позволяет нам получить доступ к какому-то из портов контейнера, пробросив его наружу (в основную операционную систему). По умолчанию, мы не можем достучаться к каким-либо из портов контейнера. Однако, в Dockerfile опция EXPOSE
позволяет нам объявить, к какому из портов мы можем обратиться из основной ОС.
Для этого, на по-быстрому, запустим Docker-образ php-apache, который работает на 80 порту.
Для начала, создадим новую папку apache (перейдём в неё cd apache
), в которой создадим файл index.php
, на основе которого мы и поймём, что всё работает.
<?php
echo 'Hello from apache. We have PHP version = ' . phpversion() . PHP_EOL;
А так же, в этой папке создадим файл Dockerfile
:
FROM php:7.2-apache
# Указываем рабочую папку
WORKDIR /var/www/html
# Копируем все файлы проекта в контейнер
COPY . /var/www/html
EXPOSE 80
Пробежимся по командам:
FROM: это вам уже знакомо, это образ с уже установленным php и apache
WORKDIR: создаст папку если она не создана, и перейдёт в неё. Аналогично выполнению команд mkdir /var/www/html && cd /var/www/html
EXPOSE: Apache по-умолчанию запускается на 80 порту, попробуем «прокинуть» его в нашу основную ОС (посмотрим как это работает через несколько секунд)
Для работы с сетью в Docker, нужно проделать 2 шага:
- Прокинуть системный порт (Expose).
- Привязать порт основной ОС к порту контейнера (выполнить соответствие).
Это что-то похоже на подключение вашей PS4 приставки к телевизору по HDMI кабелю. При подключении кабеля, вы явно указываете, какой HDMI-канал будет отображать видео.
В этой аналогии наша основная ОС будет как телевизор, а контейнер — это игровая консоль. Мы должны явно указать, какой порт основной операционной системы будет соответствовать порту контейнера.
EXPOSE в Докерфайле разрешает подключение к 80 порту контейнера — как разрешение HDMI подключения к PS4.
Выполним первый шаг прокидывания порт. Сбилдим контейнер:
docker build . --tag own_php_apache
И после этого, запустим контейнер:
docker run own_php_apache
После чего, попробуем перейти по адресу localhost:80
Но, это не сработало, потому что мы ещё не выполнили 2 шаг по маппингу портов.
Выйдите из контейнера, нажав CTRL+C.
Если у вас проблемы с остановкой контейнера, в новом окне откройте терминал, выполните
docker ps
, найдите ID контейнера, который сейчас запущен, и выполнитеdocker stop {CONTAINER_ID}
(указав ваш ID контейнера)
Теперь, осталось сообщить нашему компьютеру, какой порт контейнера ему нужно слушать, и для этого формат записи будет такой:
docker run -p <HOST_PORT>:<CONTAINER_PORT>
И мы можем указать любое соответствие портов, но сейчас просто укажем, что порт системы 80 будет слушать 80 порт контейнера:
docker run -p 80:80 own_php_apache
Здесь, вы уже наверное заметили, что добавился новый параметр -p 80:80
, который говорит Docker-у: я хочу, чтобы порт 80 из apache был привязан к моему локальному порту 80.
И теперь, если перейти по адресу localhost:80, то должны увидеть успешный ответ:
Оказывается, это даже легче, чем подключение HDMI-кабеля. Сейчас, можем попробовать выполнить запуск на разных портах:
docker run -p 8080:80 own_php_apache
Теперь, немного подчистим за собой: нужно остановить и удалить контейнеры, которые в даный момент мы запустили:
docker ps
docker stop <CONTAINER_ID> ...
docker rm <CONTAINER_ID> ...
Для *nix пользователей есть небольшой хак, который позволит остановить и удалить все контейнеры Docker:
docker stop $(docker ps -a -q) # Остановит все контейнеры docker rm $(docker ps -a -q) # Удалит все остановленные контейнеры
Запомните, что любой, кто будет запускать этот код на своём компьютере, не должен иметь установленный PHP, всё что ему нужно — один только Docker.
Docker образ: прослойка данных и кеширование
Docker умнее, чем вы могли бы подумать :).
Каждый раз, когда вы собираете образ, он кешируется в отдельный слой. Ввиду того, что образы являются неизменяемыми, их ядро никогда не модифицируются, потому применяется система кеширования, которая нужна для увеличения скорости билдинга.
Каждая команда в Dockerfile сохраняется как отельный слой образа.
Рассмотрим это на примере нашего прошлого Dockerfile-а:
FROM php:7.2-apache
# Копирует код ядра
COPY . /var/www/html
WORKDIR /var/www/html
EXPOSE 80
Когда вы пишите свой Dockerfile, вы добавляете слои поверх существующего основного образа (указанного в FROM), и создаёте свой собственный образ (Image).
FROM: говорит Докеру взять за основу этот существующий образ. А все новые команды будут добавлены слоями поверх этого основного образа.
COPY: копирует файлы с основной ОС в образ
WORKDIR: устанавливает текущую папку образа в /var/www/html
Слой Образа Докера это как точка сохранения в игре Super Mario. Если вы хотите изменить какие-то вещи, произошедшие до этой точки сохранения, то вам придётся перезапустить этот уровень полностью. Если вы хотите продолжить прогресс прохождения, вы можете начать с того места, где остановились.
Docker начинает кешировать с «того места, где остановился» во время билдинга Dockerfile. Если в Докерфайле не было никаких изменений с момента последнего билдинга, то образ будет взят полностью из кеша. Если же вы измените какую-то строку в Dockerfile — кеш будет взят только тех слоёв команд, которые находятся выше изменённой команды.
Для иллюстрации этого, добавим новые строки в Dockerfile:
FROM php:7.2-apache
WORKDIR /var/www/html
# Copy the app code
COPY . /var/www/html
RUN apt-get update && apt-get upgrade -y && apt-get install -y curl php7.2-mbstring php7.2-zip php7.2-intl php7.2-xml php7.2-json php7.2-curl
RUN echo "Hello, Docker Tutorial"
EXPOSE 80
После чего, пересоберём образ:
docker build . --tag own_php_apache
Выполнив эту команду, из вывода в консоль можете увидеть, что некоторые слои были взяты из кеша. Это как раз те команды, выше которых в Dockerfile не было добавлено/изменено содержимого.
И можно заметить, что в случае изменения Dockerfile, билдинг занимает больше времени, потому что не используется кеш. Где бы вы не написали команду, все закешированные команды, которые находятся ниже в Dockerfile, будут перебилжены заново. А те, что находятся выше, будут по-прежнему браться из кеша.
Когда вы используете команду COPY, она копирует указанную директорию в контейнер. И, в случае изменения содержимого любого из файлов этой директории, кеш команды COPY будет сброшен. Docker сверяет изменения во время билдинга в каждом из файлов. Если они были изменены, кеш будет сброшен, как и для всех последующих слоёв.
Если честно, то это действительно крутая функция. Docker следит за изменениями в файлах и использует кеш всегда, когда это нужно (когда были произведены изменения в каких-то из файлов). Изменение ваших файлов потенциально может затрагивать будущие команды, из-за чего, и все последующие слои билдятся заново, а не берутся из кеша.
Какие выводы из этого можно сделать:
- Команды, которые вероятнее всего не будут меняться в будущем, нужно помещать как можно выше в Dockerfile.
- Команды копирования данных нужно помещать ниже, потому что файлы при разработке изменяются довольно часто.
- Команды, которые требуют много времени на билдинг, нужно помещать выше.
В заключение, так же хочу сказать, как можно уменьшить размер слоёв Docker образов.
В Dockerfile вы можете иметь несколько команд (RUN) на выполнение:
RUN apt-get update
RUN apt-get install -y wget
RUN apt-get install -y curl
В результате выполнения этой команды, будет создано 3 разных слоя в образе. Вместо этого, все команды стараются объединить в одну строку:
RUN apt-get update && apt-get install -y wget curl
Если команда становится длинной, и нечитаемой, то для переноса на следующую строку делаем так:
RUN apt-get update && apt-get install -y wget curl &&
&& apt-get clean -y
&& docker-php-ext-install soap mcrypt pdo_mysql zip bcmath
Если же команда становится слишком большой, и неудобной для чтения, то можно создать новый shell скрипт, в который поместить длинную команду, и запускать этот скрипт одной простой командой RUN.
Технически, только команды ADD, COPY, и RUN создают новый слой в Docker образе, остальные команды кешируются по-другому
Что такое Docker-Compose?
Docker-compose это как дирижёр оркестра, где ваш оркестр — это набор контейнеров, которыми нужно управлять. Каждый контейнер имеет отдельную задачу, как и музыкальные инструменты в разных частях песни.
Docker Compose управляет контейнерами, запускает их вместе, в нужной последовательности, необходимой для вашего приложения.
Его можно назвать дирижёром в мире Docker-а.
Docker-compose организовывает совместных запуск контейнеров, как инструменты в групповой игре в определённых участках песни.
Каждый инструмент имеет конкретную задачу в группе оркестра. Труба создаёт основную мелодию песни; фортепиано, гитара дополняют основную мелодию; барабаны задают ритм; саксофоны добавляют больше гармонии и т.д.
Каждый из инструментов имеет свою конкретную работу и задачу, как и наши контейнеры.
Docker-compose написан в формате YAML который по своей сути похож на JSON или XML. Но YAML имеет более удобный формат для его чтения, чем вышеперечисленные. В формате YAML имеют значения пробелы и табуляции, именно пробелами отделяются названия параметров от их значений.
Создадим новый файл docker-compose.yml
, для рассмотрения синтаксиса Docker Compose:
version: '3'
services:
app:
build:
context: .
ports:
- 8080:80
Теперь, построчно разберёмся с заданными параметрами, и что они значат:
version: какая версия docker-compose используется (3 версия — самая последняя на даный момент).
services: контейнеры которые мы хотим запустить.
app: имя сервиса, может быть любым, но желательно, чтобы оно описывало суть этого контейнера.
build: шаги, описывающие процесс билдинга.
context: где находится Dockerfile, из которого будем билдить образ для контейнера.
ports: маппинг портов основной ОС к контейнеру.
Мы можем использовать этот файл для билдинга нашего предыдущего образа apache:
docker-compose build
После выполнения этой команды, Docker спарсит файл docker-compose и создаст описанные сервисы на основе инструкций во вкладке build.
А context говорит о том, из какой директории мы берём Dockerfile для создания образа сервиса (в текущем случае — это означает текущую директорию .
, но могло быть и /php-cli
, /nginx
, и т.д.).
И теперь, запустим эти сервисы, которые создали:
docker-compose up
В результате чего, сервер должен был запуститься, и стать доступным по адресу localhost:8080.
Теперь, отключитесь от консоли, нажав CTRL+C.
Когда контейнер под названием app запускается, docker-compose автоматически связывает указанные порты во вкладке ports
. Вместо того, как мы делали ранее, выполняя -v 8080:80
, docker-compose делает это за нас, получив информацию параметра ports
. Docker-compose избавляет нас боли, связанной с указанием параметров в командной строке напрямую.
С docker-compose.yml мы переносим все параметры, ранее записываемые в командной строке при запуске контейнера в конфигурационный YAML файл.
В этом примере мы записали BUILD и RUN шаги для нашего сервиса в docker-compose.yml. И преимущество такого подхода ещё в том, что теперь для билдинга и для запуска этих сервисов нам нужно запомнить только 2 команды: docker-compose build
и docker-compose up
. При таком подходе не нужно помнить, какие аргументы нужно указывать, какие опции нужно задавать при запуске контейнера.
Теперь давайте сделаем нашу разработку немного легче. Сделаем, чтобы вместо постоянного перестроения образа при каждом изменении файлов, мы можем примонтировать нашу рабочую папку в контейнер.
Для этого, удалите строку COPY . /var/www/html
с Dockerfile — теперь все файлы будут прокинуты из основной ОС. Новый Dockerfile будет иметь вид:
FROM php:7.2-apache
WORKDIR /var/www/html
RUN apt-get update && apt-get install -y wget
EXPOSE 80
Ранее мы рассматривали, как примонтировать папку в контейнер, для этого мы запускали контейнер с аргументом -v <HOST_DIRECTORY>:<CONTAINER_DIRECTORY>
.
С Docker-compose мы можем указать напрямую в docker-compose.yml:
version: '3'
services:
app:
build:
context: .
ports:
- 8080:80
volumes:
- .:/var/www/html
Добавленная строка примонтирует текущую директорию основой операционной системы к директории /var/www/html контейнера.
В отличие от указания путь в консоли, здесь можно указывать относительный путь (
.
), не обязательно указывать полный путь (C:projectsdocker-exampleapache
), как было ранее при ручном запуске контейнера.
Теперь, выполните по очереди команды:
docker-compose stop
docker-compose rm
При удалении, вас спросят, действительно ли удалять, напишите y
и нажмите кнопку enter. Эти команды остановят и удалят все контейнеры, описанные в файле docker-compose.yml (то же самое, как мы ранее запускали docker stop <CONTAINER_ID>
и docker rm <CONTAINER_ID>
)
Теперь перебилдим сервисы, потому что мы изменили Dockerfile:
docker-compose build
И заново запустим:
docker-compose up
И опять, по адресу localhost:8080 поднимется наш сервер.
Вместо того, чтобы копировать каждый раз файлы в образ, мы просто примонтировали папку, содержащую исходный код приложения. И теперь, каждый раз не придётся делать ребилд образа, когда файлы изменяются, теперь изменения происходят в лайв режиме, и будут доступны без перестройки образа.
Чтобы в этом убедиться, изменим файл index.php, добавим в него скрипт нами любимой пирамиды:
<?php
$n = $i = $_GET['count'] ?? 4;
echo '<pre>';
while ($i--) {
echo str_repeat(' ', $i).str_repeat('* ', $n - $i)."n";
}
echo '</pre>';
И теперь, если перейти по адресу localhost:8080?count=10, то увидим, что пирамида выводится:
Монтирование вашей локальной папки как Docker Volume это основной метод как разрабатывать приложения в контейнере.
Так же, как мы ранее выполняли команды внутри контейнера, указывая аргументы -it ... /bin/bash
. Docker-compose так же предоставляет интерфейс по удобному выполнению команд внутри конкретного контейнера. Для этого нужно выполнить команду:
docker-compose exec {CONTAINER_NAME} {COMMAND}
где, вместо {CONTAINER_NAME}
нужно записать имя контейнера, под которым он записан в сервисах;
а вместо {COMMAND}
— желаемую команду.
К примеру, эта команда может выглядеть так:
docker-compose exec php-cli php -v
Но, сделаем это на основе текущего Dockerfile:
docker-compose down # остановим контейнеры
docker-compose up -d # здесь используется опция -d которая сообщает, что контейнер должен висеть в режиме демона
docker-compose exec app apache2 -v
И в результате должны получить
Пока что, в docker-compose.yml описан только один сервис, потому разворачиваем мы только один контейнер. Но реальный файл docker-compose выглядит больше. К примеру, для Laravel он такой:
version: '3'
services:
nginx:
build:
context: ./
dockerfile: docker/nginx.docker
volumes:
- ./:/var/www
ports:
- "8080:80"
depends_on:
- php-fpm
php-fpm:
build:
context: ./
dockerfile: docker/php-fpm.docker
volumes:
- ./:/var/www
depends_on:
- mysql
- redis
environment:
- "DB_PORT=3306"
- "DB_HOST=mysql"
- "REDIS_PORT=6379"
- "REDIS_HOST=redis"
php-cli:
build:
context: ./
dockerfile: docker/php-cli.docker
volumes:
- ./:/var/www
depends_on:
- mysql
- redis
environment:
- "DB_PORT=3306"
- "DB_HOST=mysql"
- "REDIS_PORT=6379"
- "REDIS_HOST=redis"
tty: true
mysql:
image: mysql:5.7
volumes:
- ./storage/docker/mysql:/var/lib/mysql
environment:
- "MYSQL_ROOT_PASSWORD=secret"
- "MYSQL_USER=app"
- "MYSQL_PASSWORD=secret"
- "MYSQL_DATABASE=app"
ports:
- "33061:3306"
redis:
image: redis:3.0
ports:
- "6379:6379"
И при выполнении одной только команды docker-compose up
, поднимутся 5 сервисов. В сравнении с тем, что мы бы вручную выполняли 5 раз команду docker run ...
. Так что, использование docker-compose в этом случае — очевидно. Так что, теперь, ещё один шаг позадчи, теперь вы знаете, что такое docker и docker compose, и для чего нужен каждый из них.
Как писать Микро Сервисы с Docker? Что такое микросервисы?
Docker найболее часто используемый инструмент для написания Микросервисов. Микросервисы — это архитектурный шаблон проектирования который следует философии «разделения ответственности».
Ниже я постараюсь кратко описать, что такое микросервисы:
Одиночный миросервис выполняет одну конкретнкую задачу. Он никак не связан с другими существующими микросервисами. Вместе же, микросервисы образуют приложение.
Микросервис должен выполнять свою задачу в изолированной среде, управлять своей собственной локальной информацией, и быть независимым от общей системы настолько, насколько это возможно. В основном, каждый из микросервисов имеет собственную, отдельную базу данных (если она нужна).
Это позволяет создавать максимально гибкие и легко масштабируемые приложения.
Идея разделения по ответственности предоставляет преимущество в том, что команда разработчиков может работать параллельно, фокусируясь над разными компонентами.
В основном, микросервисы имеют канал коммуникации мужду собой, в виде REST API, который возвращает данные в JSON, или что-то типа того.
Иногда бывает неясно, насколько большой, или маленькой должна быть задача микросервиса, которую он должен решать. Это решение лежит на плечах разработчика, здесь нет чёткого правила.
Использование микросервисов позволяет быстро масшабироваться под большой нагрузкой, без масшабирования остальных частей вашего приложения. То есть, такая архитектура позволяет вам масшабировать систему компонентно, там, где это требуется. В случае монолитной, единой системы, вам придётся масшабировать всё приложение.
Ввиду того, что статья и так получилась достаточно большой, то пример реализации микросервисной архитектуры я покажу в следующей статье на эту тему. Я принял решение подготовить более качественный материал на эту тему вместе с примерами кода.
Резюме
Я попытался написать эту статью максимально просто, построив всё объяснение на аналогиях и примерах их жизни. Эта статью можно считать простой инструкцией по работе с Docker. Помимо того, что я описал, как пользоваться Docker-ом, добавив несколько рабочих примеров, которые вы можете попробовать у себя на компьютере, я добавил много дополнительной информации, и некоторых тонкостей работы с Docker-ом. Надеюсь, что эта статья показала вам, что такое Docker, и с чем его едят. В следующей статья я затрону более продвинутые темы и приведу примеры.