rascally_rabbit
@rascally_rabbit
дилетант

Развертывание web приложения на Go?

Добрый день.

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

Выбираю между несколькими языками, Go привлекает своей относительной простотой.

Прошу прощение, если вопрос "глупый", прошу не тыкать носом и хотя бы скинуть ссылку на материал для самостоятельного изучения. Но буду благодарен за более развернутый ответ, т.к. в английском не очень силен.
  • Вопрос задан
  • 6813 просмотров
Решения вопроса 3
evnuh
@evnuh
Поиск Гугл помог мне, впусти и ты его в свой дом
Как это работает, чтобы понимали. Я опишу истинно правильный путь, но долгий: (как подсказал pygame , по бенчмаркам https://gist.github.com/hgfischer/7965620 всё же нативный хттп сервер в Go быстрее, чем nginx с fcgi, т.к. у Go гавняная реализация fcgi, поэтому вместо fcgi быстрее будет обычный http proxy_pass).

1) Ставится веб-сервер нормальный, а не тот, который есть в самом Go. То есть, ставим nginx. Настраиваем ему все url маршруты, настраиваем отдачу статики.

2) За динамикой nginx будет обращаться к нашему Go демону. По протоколу fast-cgi. Именно по нему, потому что nginx его умеет и вообще он хорош (upd: но не в Go). Это короч бинарный протокол по которому nginx передаёт в нашу Go программу HTTP заголовки запроса от браузера и получает обратно HTTP ответ. Для этого ставим простейшую обёртку для fast-cgi под названием spawn-fcgi, она будет преднастраивать и запускать нашу Go программу, готовую для общения по протоколу fast-cgi.

3) На случай, если наша Go программа падает. Либо уже у нас есть система, которая следит за демонами и поднимает их в случае падения (systemd, upstart), тогда конфигурируем её, либо ставим таковую и тоже конфигурируем.

Привожу пример как это всё сделано у меня (самый популярный стек технологий) на Debian:

1) nginx
server {
	server_name otboi.****;
	listen 80;
	include fastcgi_params;
...
	
	location / {
		fastcgi_pass unix:/var/run/otboinik.sock;
	}


2) systemd конфиг, который стартует нашу Go программу, завёрнутую в spawn-fcgi
[Unit]
Description=Otboinik

[Service]
Restart=always
Environment=OTBOINIK_BIN=/opt/гыы/otboinik/bin/otboinik
Environment=OTBOINIK_PID=/var/run/otboinik.pid
Environment=OTBOINIK_USER=гыыыы
Environment=OTBOINIK_SOCKET=/var/run/otboinik.sock
Environment=OTBOINIK_SOCKET_USER=гыыыыы
Environment=OTBOINIK_SOCKET_MODE=0666
ExecStart=/usr/bin/spawn-fcgi -s $OTBOINIK_SOCKET -M $OTBOINIK_SOCKET_MODE -n -P $OTBOINIK_PID -u $OTBOINIK_USER -U $OTBOINIK_SOCKET_USER -G $OTBOINIK_SOCKET_USER $OTBOINIK_BIN

[Install]
WantedBy=multi-user.target


3) Сам Go код
import (
	"net/http"
	"net/http/fcgi"
)

type Server struct {
}

func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
       // чиста пример
        jsonblob := r.FormValue("events")
	if jsonblob == "" {
		w.WriteHeader(http.StatusNotAcceptable)
		return
	}
}

func main() {
	server := Server{}

	func() {
		fcgi.Serve(nil, server)
	}()

	waitchan := make(chan int, 1)
	<-waitchan
}
Ответ написан
mirrr
@mirrr
Программист и просто хороший человек
Опишу свой способ, который перекликается со способом Алексей . Все это делается одним bash-скриптом, но распишу примерный алгоритм.

1) Создаем юзера под которым будет работать приложение и переключаемся на него:
useradd -s /bin/bash <имя_пользователя>
su <имя_пользователя>


2) Генерируем новый ключ для деплоя
ssh-keygen -t rsa -C "<имя_пользователя>@<домен_сервиса>"
cat ~/.ssh/id_rsa.pub

Например, в gitlab добавляем этот ключ Project>Settings>Deploy Key

3) Клонируем приложение и собираем приложение
cd ~
git clone ssh://______.git app 
# здесь не буду расписывать, можно устанавливать через go get и т.д. способы отличаются
# для go get нужно прописать $GOPATH в .bash_profile


4) Создаем systemd service
exit #выходим из-под юзера
nano /etc/systemd/system/<service_name>.service

Вписываем:
[Unit]
Description=<description>

[Service]
Restart=always
RestartSec=10
EnvironmentFile=-/<service_path>/env
WorkingDirectory=/<service_path>/appDir
ExecStart=/<service_path>/appDir/appName
LimitNOFILE=524576
LimitNPROC=524576
User=<user>
Group=<userGroup>
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=<service_name>


[Install]
WantedBy=multi-user.target


5) Запускаем сервис и ставим в автозагрузку:

systemctl start <имя_сервиса>
systemctl enable <имя_сервиса>


Посмотреть статус:

systemctl status <имя_сервиса>

6) Разрешаем просмотр логов и перезапуск сервиса под созданным пользователем
Добавляем в /etc/sudoers строчки:

Defaults:<имя_пользователя> !authenticate
<имя_пользователя> ALL=/usr/bin/systemctl restart <имя_сервиса>, /usr/bin/systemctl stop <имя_сервиса>, /usr/bin/systemctl start <имя_сервиса>, /usr/bin/journalctl


Теперь эти операции не будут требовать пароля:
sudo journalctl -f  -u <имя_сервиса> 
sudo systemctl stop <имя_сервиса>
sudo systemctl start <имя_сервиса>
sudo systemctl restart <имя_сервиса>


7) настраиваем виртуальный хост nginx для проксирования на порт приложения, если требуется:
server {
    listen 80;
    server_name site.ru;

    client_max_body_size 256m;
    access_log  /var/log/nginx-site-acc;
    error_log /var/log/nginx-site-err;
    log_not_found off;

    location ^~ / {
        proxy_pass http://localhost:<порт_приложения>;
        proxy_set_header Host $host:$server_port;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffer_size 16k;
        proxy_buffers 32 16k;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
    }

    location ^~ /files {
        alias /home/<имя_пользователя>/app/some_files;
    }
}
Ответ написан
Комментировать
Я тестирую все на локальном сервере под Windows, потом в VirtualBox в Linux Mint собираю для Linux 64-bit.
Заливаю бинарник и все необходимые файлы на CentOS 7. Там настроен nginx в качестве прокси для отдачи статики.
Сложности возникли с запуском бинарника как демона. Всякие варианты разбирал примерно день. Остановился на следующем:

1. Создать файл mysite.service в /usr/lib/systemd/system. Это примитивнейший вариант.
[Unit]
Description=MySite HTTP Service
[Service]
# Здесь main бинарник GO
ExecStart=/home/mysite.ru/main
[Install]
WantedBy=multi-user.target


2. Запустить systemctl enable mysite.service
После изменений mysite.service нужно запускать systemctl daemon-reload

3. Запустить systemctl start mysite.service

Всё.
Прочитать про systemd можно здесь
www.freedesktop.org/software/systemd/man/systemd.s...
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@kshvakov
Если хотите просто запускать "бинарник" поставьте supervisord.d, конфиг простой


[program:you_program_name]
command=/opt/bin/you_program
numprocs=1
autostart=true
autorestart=true
startsecs=10
startretries=5
exitcodes=0,2
stopsignal=TERM
stopwaitsecs=10


управлять:
sudo supervisorctl status
sudo supervisorctl start/restart you_program_name
Ответ написан
Olej
@Olej
инженер, программист, преподаватель
Выбираю между несколькими языками, Go привлекает своей относительной простотой.

Язык программирования Go
Русскоязычный подкаст о Go
Там вы найдёте...
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы