Поиск по сайту:

Как развернуть веб-приложение Go с помощью Docker и Nginx в Ubuntu 22.04


Автор выбрал программу Write for DOnations.

Введение

Docker Compose — это инструмент оркестрации контейнеров, который соответствует требованиям современных приложений. Он позволяет запускать несколько взаимосвязанных контейнеров одновременно. Вместо ручного запуска контейнеров инструменты оркестрации дают разработчикам возможность одновременно контролировать, масштабировать и расширять контейнер.

Преимущества использования Nginx в качестве внешнего веб-сервера заключаются в производительности, возможности настройки и завершении TLS, что освобождает приложение от выполнения этих задач. Надстройка может сопровождать nginx-proxy для автоматизации генерации и обновления сертификатов для проксируемых контейнеров.

В этом руководстве вы развернете пример веб-приложения Go с gorilla/mux в качестве маршрутизатора запросов и Nginx в качестве веб-сервера, все внутри контейнеров Docker, которые управляются Docker Compose. Вы будете использовать nginx-proxy с надстройкой Let’s Encrypt в качестве обратного прокси. В конце этого руководства вы развернете веб-приложение Go, доступное в вашем домене с несколькими маршрутами, используя Docker и защищенное сертификатами Let’s Encrypt.

Предпосылки

  • Сервер Ubuntu 22.04 с привилегиями root и дополнительной учетной записью без полномочий root. Вы можете настроить это, следуя этому руководству по начальной настройке сервера. В этом руководстве пользователем без полномочий root является sammy.
  • Docker устанавливается, выполнив первые два шага инструкции по установке Docker в Ubuntu 22.04.
  • Docker Compose устанавливается, следуя первому шагу инструкции по установке Docker Compose в Ubuntu 22.04.
  • Полностью зарегистрированное доменное имя. В этом руководстве будет использоваться ваш_домен. Вы можете получить его бесплатно на Freenom или воспользоваться услугами регистратора доменов по вашему выбору.
  • Запись DNS \A с your_domain, указывающая на общедоступный IP-адрес вашего сервера. Подробную информацию о том, как их добавить, см. в этом введении в DigitalOcean DNS.
  • Понимание Docker и его архитектуры. Введение в Docker см. в статье Экосистема Docker: введение в общие компоненты.

Шаг 1 — Создание примера веб-приложения Go

На этом шаге вы настроите свое рабочее пространство и создадите простое веб-приложение Go, которое позже вы поместите в контейнер. Приложение Go будет использовать мощный маршрутизатор запросов gorilla/mux, выбранный за его гибкость и скорость.

В этом руководстве вы будете хранить все данные в ~/go-docker. Выполните следующую команду, чтобы создать эту папку:

  1. mkdir ~/go-docker

Перейдите к нему:

  1. cd ~/go-docker

Вы сохраните свой пример веб-приложения Go в файле с именем main.go. Создайте его с помощью текстового редактора:

  1. nano main.go

Добавьте следующие строки:

package main

import (
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
)

func main() {
	r := mux.NewRouter()

	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "<h1>This is the homepage. Try /hello and /hello/Sammy\n</h1>")
	})

	r.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "<h1>Hello from Docker!\n</h1>")
	})

	r.HandleFunc("/hello/{name}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		title := vars["name"]

		fmt.Fprintf(w, "<h1>Hello, %s!\n</h1>", title)
	})

	http.ListenAndServe(":80", r)
}

Сначала вы импортируете пакеты net/http и gorilla/mux, которые обеспечивают функциональность HTTP-сервера и маршрутизацию. Пакет gorilla/mux реализует более мощный маршрутизатор запросов и диспетчер, сохраняя при этом совместимость интерфейса со стандартным маршрутизатором. Вы создаете экземпляр нового маршрутизатора mux и сохраняете его в переменной r.

Затем вы определяете три маршрута: /, /hello и /hello/{name}. Первая (/) служит домашней страницей, и вы включаете сообщение для страницы. Второй (/hello) возвращает посетителю приветствие. Для третьего маршрута (/hello/{name}) вы указываете, что он должен принимать имя в качестве параметра и отображать приветственное сообщение со вставленным именем.

В конце вашего файла вы запускаете HTTP-сервер с помощью http.ListenAndServe и указываете ему прослушивать порт 80, используя настроенный вами маршрутизатор.

Сохраните и закройте файл.

Перед запуском приложения Go вам необходимо скомпилировать и упаковать его для выполнения внутри контейнера Docker. Go — это компилируемый язык, поэтому перед запуском программы компилятор переводит программный код в исполняемый машинный код.

Вы настроили свое рабочее пространство и создали пример веб-приложения Go. Затем вы развернете nginx-proxy с автоматическим предоставлением сертификата Let’s Encrypt.

Шаг 2 — Развертывание nginx-прокси с помощью Let’s Encrypt

Важно, чтобы ваше приложение было защищено с помощью HTTPS. Для этого вы развернете nginx-proxy через Docker Compose вместе с надстройкой Let’s Encrypt. Эта настройка защищает контейнеры Docker, проксируемые с помощью nginx-proxy, и обеспечивает безопасность вашего приложения через HTTPS, автоматически обрабатывая создание и обновление сертификата TLS.

Вы будете хранить конфигурацию Docker Compose для nginx-proxy в файле с именем nginx-proxy-compose.yaml. Создайте его, запустив:

  1. nano nginx-proxy-compose.yaml

Добавьте в файл следующие строки:

version: '3'

services:
  nginx-proxy:
    restart: always
    image: jwilder/nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/etc/nginx/vhost.d"
      - "/usr/share/nginx/html"
      - "/var/run/docker.sock:/tmp/docker.sock:ro"
      - "/etc/nginx/certs"

  letsencrypt-nginx-proxy-companion:
    restart: always
    image: jrcs/letsencrypt-nginx-proxy-companion
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    volumes_from:
      - "nginx-proxy"

В этом файле вы определяете два контейнера: один для nginx-proxy и один для надстройки Let’s Encrypt (letsencrypt-nginx-proxy-companion). Для прокси-сервера вы указываете образ jwilder/nginx-proxy, предоставляете и сопоставляете порты HTTP и HTTPS и определяете тома, которые будут доступны для контейнера для сохранения данных, связанных с Nginx.

Во втором блоке вы называете образ для конфигурации надстройки Let’s Encrypt. Затем вы настраиваете доступ к сокету Docker, определяя том, а затем существующие тома из прокси-контейнера для наследования. Оба контейнера имеют свойство restart, для которого задано значение always, что указывает Docker всегда поддерживать их (в случае сбоя или перезагрузки системы).

Сохраните и закройте файл.

Разверните nginx-proxy, выполнив:

  1. docker compose -f nginx-proxy-compose.yaml up -d

Docker Compose принимает пользовательский именованный файл с помощью флага -f. Команда up запускает контейнеры, а флаг -d (отключенный режим) указывает запускать контейнеры в фоновом режиме.

Вы получите такой вывод:

Output
[+] Running 21/21 ⠿ letsencrypt-nginx-proxy-companion Pulled 6.8s ⠿ df9b9388f04a Pull complete 3.1s ⠿ 6c6cfd4eaf5b Pull complete 3.9s ⠿ 870307501973 Pull complete 4.3s ⠿ e8ff3435d14f Pull complete 4.5s ⠿ 5b78ba945919 Pull complete 4.8s ⠿ 973b2ca26006 Pull complete 5.0s ⠿ nginx-proxy Pulled 8.1s ⠿ 42c077c10790 Pull complete 3.9s ⠿ 62c70f376f6a Pull complete 5.5s ⠿ 915cc9bd79c2 Pull complete 5.6s ⠿ 75a963e94de0 Pull complete 5.7s ⠿ 7b1fab684d70 Pull complete 5.7s ⠿ db24d06d5af4 Pull complete 5.8s ⠿ e917373dbecf Pull complete 5.9s ⠿ 11e2be9775e9 Pull complete 5.9s ⠿ 9996fa75bc02 Pull complete 6.1s ⠿ d37674efdf77 Pull complete 6.3s ⠿ a45d84576e75 Pull complete 6.3s ⠿ a13c1f42faf7 Pull complete 6.4s ⠿ 4f4fb700ef54 Pull complete 6.5s [+] Running 3/3 ⠿ Network go-docker_default Created 0.1s ⠿ Container go-docker-nginx-proxy-1 Started 0.5s ⠿ Container go-docker-letsencrypt-nginx-proxy-companion-1 Started 0.8s

Вы развернули nginx-proxy и его компаньон Let’s Encrypt с помощью Docker Compose. Далее вы создадите Dockerfile для своего веб-приложения Go.

Шаг 3 — Докеризация веб-приложения Go

В этом разделе вы подготовите Dockerfile, содержащий инструкции о том, как Docker создаст неизменяемый образ для вашего веб-приложения Go. Docker создает неизменяемый образ приложения, аналогичный моментальному снимку контейнера, используя инструкции, содержащиеся в Dockerfile. Неизменяемость образа гарантирует одинаковую среду каждый раз, когда запускается контейнер, основанный на конкретном образе.

Создайте Dockerfile в текстовом редакторе:

  1. nano Dockerfile

Добавьте следующие строки:

FROM golang:alpine AS build
RUN apk --no-cache add gcc g++ make git
WORKDIR /go/src/app
COPY . .
RUN go mod init webserver
RUN go mod tidy
RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/web-app ./main.go

FROM alpine:3.17
RUN apk --no-cache add ca-certificates
WORKDIR /usr/bin
COPY --from=build /go/src/app/bin /go/bin
EXPOSE 80
ENTRYPOINT /go/bin/web-app --port 80

Этот Dockerfile состоит из двух этапов. На первом этапе используется база golang:alpine, которая содержит предустановленный Go для Alpine Linux.

Затем вы устанавливаете gcc, g++, make и git в качестве необходимых инструментов компиляции для вашего приложения Go. Вы устанавливаете рабочий каталог /go/src/app, который находится под GOPATH по умолчанию. Вы также копируете содержимое текущего каталога в контейнер. Первый этап завершается рекурсивным получением пакетов, используемых из кода, и компиляцией файла main.go для выпуска без символов и отладочной информации (путем передачи -ldflags=-s -w).

Примечание. Когда вы компилируете программу Go, она сохраняет отдельную часть двоичного файла, которая будет использоваться для отладки; однако эта дополнительная информация использует память, и ее не нужно сохранять при развертывании в производственной среде.

Второй этап основан на alpine:3.17 (Alpine Linux 3.17). Он устанавливает доверенные сертификаты CA, копирует скомпилированные двоичные файлы приложения из первого этапа в текущий образ, предоставляет порт 80 и устанавливает двоичный файл приложения в качестве точки входа в образ.

Сохраните и закройте файл.

Вы создали Dockerfile для своего приложения Go, которое будет извлекать его пакеты, компилировать их для выпуска и запускать после создания контейнера. На следующем шаге вы создадите файл Docker Compose yaml и протестируете приложение, запустив его в Docker.

Шаг 4 — Создание и запуск файла Docker Compose

Теперь вы создадите файл конфигурации Docker Compose и напишите необходимую конфигурацию для запуска образа Docker, созданного на предыдущем шаге. Затем вы запустите его и проверите, правильно ли он работает. Как правило, в файле конфигурации Docker Compose указываются контейнеры, параметры, сети и тома, которые требуются приложению. Вы также можете указать, что эти элементы начинаются и останавливаются как один.

Вы сохраните конфигурацию Docker Compose для веб-приложения Go в файле с именем go-app-compose.yaml. Создайте его, запустив:

  1. nano go-app-compose.yaml

Добавьте в этот файл следующие строки:

version: '3'
services:
  go-web-app:
    restart: always
    build:
      dockerfile: Dockerfile
      context: .
    environment:
      - VIRTUAL_HOST=your_domain
      - LETSENCRYPT_HOST=your_domain

Замените your_domain оба раза своим доменным именем. Сохраните и закройте файл.

Эта конфигурация Docker Compose содержит один контейнер (go-web-app), который будет вашим веб-приложением Go. Он создает приложение, используя Dockerfile, который вы создали на предыдущем шаге, и использует текущий каталог, содержащий исходный код, в качестве контекста для сборки. Кроме того, он устанавливает две переменные среды: VIRTUAL_HOST и LETSENCRYPT_HOST. nginx-proxy использует VIRTUAL_HOST, чтобы узнать, с какого домена принимать запросы. LETSENCRYPT_HOST указывает доменное имя для создания сертификатов TLS и должно совпадать с VIRTUAL_HOST, если вы не укажете домен с подстановочными знаками.

Теперь запустите веб-приложение Go в фоновом режиме через Docker Compose:

  1. docker compose -f go-app-compose.yaml up -d

Вывод, подобный этому, будет напечатан (этот вывод был усечен для удобочитаемости):

Output
Creating network "go-docker_default" with the default driver Building go-web-app Step 1/13 : FROM golang:alpine AS build ---> b97a72b8e97d ... Successfully built 71e4b1ef2e25 Successfully tagged go-docker_go-web-app:latest ... [+] Running 1/1 ⠿ Container go-docker-go-web-app-1 Started

Если вы просматриваете выходные данные, представленные после выполнения команды, Docker регистрирует каждый шаг создания образа приложения в соответствии с конфигурацией в вашем Dockerfile.

Теперь вы можете перейти по адресу https://ваш_домен/, чтобы получить доступ к своей домашней странице. По домашнему адресу вашего веб-приложения вы можете получить доступ к странице в результате маршрута /, который вы определили на первом шаге.

Теперь перейдите к https://ваш_домен/hello. Будет загружено сообщение, которое вы определили в своем коде для маршрута /hello из шага 1.

Наконец, добавьте имя к адресу вашего веб-приложения, чтобы проверить другой маршрут, например: https://your_domain/hello/Sammy.

Примечание. Если вы получили сообщение об ошибке о недействительных сертификатах TLS, подождите несколько минут, пока надстройка Let’s Encrypt предоставит сертификаты. Если вы по-прежнему получаете сообщения об ошибках через короткое время, дважды проверьте введенные вами команды и настройки на этом шаге.

Вы создали файл Docker Compose и написали конфигурацию для запуска вашего приложения Go внутри контейнера. Чтобы закончить, вы перешли в свой домен, чтобы убедиться, что настройка маршрутизатора gorilla/mux правильно обрабатывает запросы к вашему веб-приложению Dockerized Go.

Заключение

Вы успешно развернули веб-приложение Go с Docker и Nginx в Ubuntu 22.04. С Docker обслуживание приложений не занимает много времени, потому что среда, в которой выполняется приложение, гарантированно будет неизменной при каждом запуске. Официальные документы.