🐳 Как ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ многоступСнчатый Dockerfile для .NET Core

by itisgood
Если Π²Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚Π΅ с .NET Core ΠΈ Docker, Ρ‚ΠΎ навСрняка задавались вопросом, ΠΊΠ°ΠΊ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ свои ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π½Ρ‹Π΅ прилоТСния Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΌΠΈ, быстрыми ΠΈ бСзопасными.

Π—Π°Ρ‡Π΅ΠΌ Π½ΡƒΠΆΠ½Ρ‹ многоступСнчатыС Docker-Ρ„Π°ΠΉΠ»Ρ‹?

ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅ сСбС: Ρƒ вас Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ .NET Core – Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, нСбольшой API ΠΈΠ»ΠΈ Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ – ΠΈ Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ Π΅Π³ΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ.
Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ просто Π·Π°ΠΏΠΈΡ…Π½ΡƒΡ‚ΡŒ всС Π² ΠΎΠ΄ΠΈΠ½ Dockerfile, Π½ΠΎ Ρ‚ΠΎΠ³Π΄Π° Π²Ρ‹ Π±ΡƒΠ΄Π΅Ρ‚Π΅ Ρ‚Π°ΡΠΊΠ°Ρ‚ΡŒ с собой вСсь .NET SDK, инструмСнты сборки ΠΈ ΠΊΡƒΡ‡Ρƒ всСго, Ρ‡Ρ‚ΠΎ Π²Π°ΠΌ Π½Π΅ понадобится, ΠΊΠΎΠ³Π΄Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ запустится.
Π­Ρ‚ΠΎ всС Ρ€Π°Π²Π½ΠΎ Ρ‡Ρ‚ΠΎ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ Π² ΠΏΠΎΠ΅Π·Π΄ΠΊΡƒ вСсь Π½Π°Π±ΠΎΡ€ инструмСнтов, ΠΊΠΎΠ³Π΄Π° Π½ΡƒΠΆΠ½Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΡ‚Π²Π΅Ρ€Ρ‚ΠΊΠ°.
ΠœΠ½ΠΎΠ³ΠΎΡΡ‚ΡƒΠΏΠ΅Π½Ρ‡Π°Ρ‚Ρ‹Π΅ Docker-Ρ„Π°ΠΉΠ»Ρ‹ Ρ€Π°Π·Π΄Π΅Π»ΡΡŽΡ‚ процСсс Π½Π° – Π²Ρ‹ ΡƒΠ³Π°Π΄Π°Π»ΠΈ – этапы.
На ΠΎΠ΄Π½ΠΎΠΌ этапС выполняСтся тяТСлая Ρ€Π°Π±ΠΎΡ‚Π° ΠΏΠΎ созданию прилоТСния, Π° Π½Π° Π΄Ρ€ΡƒΠ³ΠΎΠΌ – Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ΠΉ ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚ ΠΈ Π΅Π³ΠΎ запуск.
Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚?
МСньшиС ΠΎΠ±Ρ€Π°Π·Ρ‹, мСньший объСм ΠΈ Π±ΠΎΠ»Π΅Π΅ счастливый ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€ развСртывания.
ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, это шанс ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π½Π°Π²Ρ‹ΠΊΠΈ Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Docker ΠΈ ΠΏΠΎΡ‡ΡƒΠ²ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ сСбя Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ волшСбником.

Π”Π°Π²Π°ΠΉΡ‚Π΅ собСрСм

Π’ΠΎΡ‚ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ многоступСнчатого Dockerfile для прилоТСния .NET Core.
ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‚ΡŒ Π΅Π³ΠΎ ΠΏΠΎ Ρ…ΠΎΠ΄Ρƒ Π΄Π΅Π»Π°.
# Stage 1: Build environment
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src

# Copy csproj and restore dependencies
COPY *.csproj ./
RUN dotnet restore

# Copy the rest of the code
COPY . ./
RUN dotnet build -c Release --no-restore

# Publish the app
RUN dotnet publish -c Release -o /app --no-restore

# Stage 2: Runtime environment
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app

# Add a non-root user for security
RUN useradd -m -r -u 1000 appuser

# Copy the published files
COPY --from=build /app ./

# Set ownership
RUN chown -R appuser:appuser /app

# Switch to non-root user
USER appuser

# Expose the port
EXPOSE 8080

# Set the entry point
ENTRYPOINT ["dotnet", "YourAppName.dll"]

Π­Ρ‚Π°ΠΏ 1: сборка

ΠŸΠ΅Ρ€Π²Π°Ρ Ρ‡Π°ΡΡ‚ΡŒ, обозначСнная ΠΊΠ°ΠΊ сборка, – это Ρ‚ΠΎ мСсто, Π³Π΄Π΅ происходит всС Π²ΠΎΠ»ΡˆΠ΅Π±ΡΡ‚Π²ΠΎ.

ΠœΡ‹ Π½Π°Ρ‡ΠΈΠ½Π°Π΅ΠΌ с ΠΎΠ±Ρ€Π°Π·Π° .NET SDK (mcr.microsoft.com/dotnet/sdk:8.0).

Π’ Π½Π΅ΠΌ Π΅ΡΡ‚ΡŒ всС, Ρ‡Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ для компиляции нашСго ΠΊΠΎΠ΄Π°: SDK, инструмСнты, всС ΠΎΡΡ‚Π°Π»ΡŒΠ½ΠΎΠ΅.

ΠœΡ‹ установили Π² качСствС Ρ€Π°Π±ΠΎΡ‡Π΅Π³ΠΎ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π° /src, просто Ρ‡Ρ‚ΠΎΠ±Ρ‹ всС Π±Ρ‹Π»ΠΎ Π°ΠΊΠΊΡƒΡ€Π°Ρ‚Π½ΠΎ.

Π‘Π½Π°Ρ‡Π°Π»Π° ΠΌΡ‹ ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅ΠΌ Ρ„Π°ΠΉΠ» .csproj ΠΈ запускаСм dotnet restore.

ΠŸΠΎΡ‡Π΅ΠΌΡƒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ„Π°ΠΉΠ» ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°?

Π­Ρ‚ΠΎ Ρ‚Ρ€ΡŽΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ я подсмотрСл – Docker ΠΊΡΡˆΠΈΡ€ΡƒΠ΅Ρ‚ слои, поэтому Ссли ваши зависимости Π½Π΅ измСнились, ΠΎΠ½ пропускаСт шаг восстановлСния ΠΏΡ€ΠΈ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ сборкС.

Π­Ρ‚ΠΎ экономит ΠΊΡƒΡ‡Ρƒ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ.

Π—Π°Ρ‚Π΅ΠΌ я ΠΏΠ΅Ρ€Π΅Π½ΠΎΡˆΡƒ ΠΎΡΡ‚Π°Π»ΡŒΠ½ΠΎΠΉ ΠΊΠΎΠ΄ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ COPY . ./ ΠΈ Π·Π°ΠΏΡƒΡΠΊΠ°ΡŽ dotnet build. Π€Π»Π°Π³ –no-restore Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ Π΅ΠΌΡƒ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠΆΠ΅ ΡΠΏΡ€Π°Π²ΠΈΠ»ΠΈΡΡŒ с зависимостями.

НаконСц, dotnet publish Π²Ρ‹ΠΏΠ»Π΅Π²Ρ‹Π²Π°Π΅Ρ‚ скомпилированноС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² ΠΏΠ°ΠΏΠΊΡƒ /app.

Π­Ρ‚ΠΎ наш Π·ΠΎΠ»ΠΎΡ‚ΠΎΠΉ Π±ΠΈΠ»Π΅Ρ‚ Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ этап.

Π­Ρ‚Π°ΠΏ 2: Runtime

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Ρƒ.

На этапС выполнСния ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π·: mcr.microsoft.com/dotnet/aspnet:8.0.

Π­Ρ‚ΠΎ просто срСда выполнСния ASP.NET – Π½ΠΈ SDK, Π½ΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ Π±Π°Π³Π°ΠΆΠ°.

Π’ качСствС Ρ€Π°Π±ΠΎΡ‡Π΅Π³ΠΎ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π° я Π²Ρ‹Π±Ρ€Π°Π» /app, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ Ρ‚Π°ΠΌ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΆΠΈΡ‚ΡŒ.

Π‘Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ ΠΈΠΌΠ΅Π΅Ρ‚ большоС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, поэтому я добавляю ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, Π½Π΅ ΡΠ²Π»ΡΡŽΡ‰Π΅Π³ΠΎΡΡ root, ΠΏΠΎΠ΄ ΠΈΠΌΠ΅Π½Π΅ΠΌ appuser.

Π Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΎΡ‚ ΠΈΠΌΠ΅Π½ΠΈ root Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅ – всС Ρ€Π°Π²Π½ΠΎ Ρ‡Ρ‚ΠΎ ΠΎΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π²Ρ…ΠΎΠ΄Π½ΡƒΡŽ Π΄Π²Π΅Ρ€ΡŒ Π½Π΅Π·Π°ΠΏΠ΅Ρ€Ρ‚ΠΎΠΉ, Π½Π΅ самая Π»ΡƒΡ‡ΡˆΠ°Ρ идСя.

Π—Π°Ρ‚Π΅ΠΌ я Π·Π°Π±ΠΈΡ€Π°ΡŽ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ со стадии сборки с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ COPY –from=build /app ./. Быстрый chown ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚ ΠΏΡ€Π°Π²Π° Π½Π° appuser, Π° USER appuser Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ ΠΎΡ‚ ΠΈΠΌΠ΅Π½ΠΈ root.

Π― ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°ΡŽ ΠΏΠΎΡ€Ρ‚ 8080 (Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π΅Π³ΠΎ, Ссли вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π΄Ρ€ΡƒΠ³ΠΎΠ΅), ΠΈ ENTRYPOINT запускаСт ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ с dotnet YourAppName.dll.

НС Π·Π°Π±ΡƒΠ΄ΡŒΡ‚Π΅ Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ сюда имя вашСй Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΉ DLL!

Запуск

Π§Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ всС Π² дСйствии, ΠΎΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» Π² ΠΏΠ°ΠΏΠΊΠ΅ с ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠΌ ΠΈ запуститС Π΅Π³ΠΎ:

docker build -t mycoolapp . docker run -p 8080:8080 mycoolapp

НаТмитС http://localhost:8080 Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅, ΠΈ Π±ΡƒΠΌ – вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π³ΠΎΡ‚ΠΎΠ²ΠΎ ΠΊ Ρ€Π°Π±ΠΎΡ‚Π΅.

Π˜Ρ‚Π°ΠΊ, Π² Ρ‡Π΅ΠΌ ΠΆΠ΅ Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π²Ρ‹Π³ΠΎΠ΄Π°?

Π’ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹ΠΉ ΠΎΠ±Ρ€Π°Π· получаСтся ΠΊΡ€ΠΎΡˆΠ΅Ρ‡Π½Ρ‹ΠΌ ΠΏΠΎ ΡΡ€Π°Π²Π½Π΅Π½ΠΈΡŽ с одноэтапной сборкой.

Π’Ρ‹ Π½Π΅ таскаСтС с собой SDK ΠΈΠ»ΠΈ инструмСнты сборки – Ρ‚ΠΎΠ»ΡŒΠΊΠΎ срСда выполнСния ΠΈ вашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, это Π±ΠΎΠ»Π΅Π΅ бСзопасно ΠΏΡ€ΠΈ использовании Π½Π΅ root-ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.

А благодаря ΠΊΡΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡŽ Docker ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π° Π½Π΅ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ пСрСсозданиС всСго с нуля.

МСньшиС ΠΎΠ±Ρ€Π°Π·Ρ‹ ΠΎΠ·Π½Π°Ρ‡Π°ΡŽΡ‚ Π±ΠΎΠ»Π΅Π΅ быстроС Ρ€Π°Π·Π²Π΅Ρ€Ρ‚Ρ‹Π²Π°Π½ΠΈΠ΅, Π° постоянство Docker позволяСт ΠΌΠ½Π΅ Π½Π΅ Π±ΠΎΡ€ΠΎΡ‚ΡŒΡΡ с ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°ΠΌΠΈ Β«Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½Π° ΠΌΠΎΠ΅ΠΉ машинС».

Настройки ΠΈ совСты

Π­Ρ‚ΠΎ надСТная отправная Ρ‚ΠΎΡ‡ΠΊΠ°, Π½ΠΎ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠ΄ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Π΅Π΅ ΠΏΠΎΠ΄ свои Π½ΡƒΠΆΠ΄Ρ‹.

НуТна ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° хэлс Ρ‡Π΅ΠΊ ?

Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅:

HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/health || exit 1
Π£ вас Π΅ΡΡ‚ΡŒ постоянныС Π΄Π°Π½Π½Ρ‹Π΅?
Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Ρ‚ΠΎΠΌ:
VOLUME /app/data
А Ссли Π²Ρ‹ ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚Π΅ΡΡŒ Π½Π° нСсколько Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€, ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚Π΅ строку FROM с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° –platform=$BUILDPLATFORM.
ΠŸΠΎΠ΄ΠΎΠ±Π½Ρ‹Π΅ нСбольшиС настройки ΠΌΠΎΠ³ΡƒΡ‚ принСсти ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡŒΠ·Ρ‹.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

ΠœΠ½ΠΎΠ³ΠΎΡΡ‚ΡƒΠΏΠ΅Π½Ρ‡Π°Ρ‚Ρ‹Π΅ Docker-Ρ„Π°ΠΉΠ»Ρ‹ стали ΠΌΠΎΠ΅ΠΉ ΠΏΠ°Π»ΠΎΡ‡ΠΊΠΎΠΉ-Π²Ρ‹Ρ€ΡƒΡ‡Π°Π»ΠΎΡ‡ΠΊΠΎΠΉ для ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ .NET Core.

Они Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ настройки, Π½ΠΎ ΠΊΠ°ΠΊ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π²Ρ‹ освоитС ΠΈΡ…, всС ΠΏΠΎΠΉΠ΄Π΅Ρ‚ ΠΊΠ°ΠΊ ΠΏΠΎ маслу.

Π’Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚Π΅ Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€, Π³ΠΎΡ‚ΠΎΠ²Ρ‹ΠΉ ΠΊ Ρ€Π°Π±ΠΎΡ‚Π΅ ΠΎΡ‚ сборки Π΄ΠΎ выполнСния.

ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ Π΅Π³ΠΎ Π² своСм ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅ – навСрняка Π²Ρ‹ ΡƒΠ΄ΠΈΠ²ΠΈΡ‚Π΅ΡΡŒ, ΠΊΠ°ΠΊ Ρ€Π°Π½ΡŒΡˆΠ΅ ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠ»ΠΈΡΡŒ Π±Π΅Π· Π½Π΅Π³ΠΎ.

см. Ρ‚Π°ΠΊΠΆΠ΅:

 

Loading

You may also like

Leave a Comment