Рубрики
Uncategorized

Использование NIX для развертывания веб -приложения Haskell в Heroku

Развертывание Ruby on Rails Apps в Heroku всегда было восхищением, и теперь, когда у них есть реестр контейнеров, другие время заезда также восхитительно развернуты. Сборки не требуются. Tagged with Nix, Haskell, Devops, Docker.

Первоначально опубликовано здесь .

Допустим, мы написали веб -приложение в Haskell.

$ curl http://localhost:8000/hello/World
Hello, World!

$ curl http://localhost:8000/hello/Haskell
Hello, Haskell!

Было бы неплохо, если бы мы могли поделиться этим с другими людьми. Давайте развернуть эту замечательную вещь для Интернет Используя Heroku.

Хаскелл и Никс

Спасибо Nix Использование упаковки Haskell Community Up Bibraries and Executive Armentables очень удобно.

Во -первых, мы сделаем каталог для нашего проекта.

~ $ mkdir haskell-on-heroku
~ $ cd $_
~/haskell-on-heroku $

Тогда мы можем попросить Cabal, чтобы мы начали с каркаса.

~/haskell-on-heroku $ nix run \
> nixpkgs.cabal-install \
> --command cabal init \
> --minimal \
> --cabal-version=2.4

Наконец, мы добавляем default.nix который использует Cabal2nix Анкет

{ haskellPackages ? (import  {}).haskellPackages
}:
  haskellPackages
    .callCabal2nix "haskell-on-heroku" ./. {}

И теперь он готов попробовать.

~/haskell-on-heroku $ nix run \
> --file default.nix \
> env --command cabal new-run
# ...
Hello, Haskell!

Удивительное веб -приложение

Наш веб -сервер использует изящную библиотеку Haskell Сервер слуги Так что нам нужно добавить это и Варп как зависимость от Haskell-on-heroku.cabal Анкет

 executable haskell-on-heroku
   main-is:             Main.hs
   build-depends:       base >=4.12 && <4.13
+                     , servant-server
+                     , warp
   default-language:    Haskell2010

Нам, вероятно, также нужно поместить реализацию нашего приложения в Main.hs Анкет

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall #-}

module Main where

import Control.Applicative ((<|>))
import Data.Proxy (Proxy (Proxy))
import Network.Wai.Handler.Warp (run)
import Servant
  ( (:>),
    Capture,
    Get,
    Handler,
    PlainText,
    serve,
  )
import System.Environment (getEnv)

type Greeter =
  "hello"
    :> Capture "name" String
    :> Get '[PlainText] String

greet :: String -> Handler String
greet name = 
  pure $ "Hello, " <> name <> "!"

getPort :: IO Int
getPort =
  read <$> getEnv "PORT" <|> pure 8000

main :: IO ()
main = do
  port <- getPort
  run port $ serve (Proxy @Greeter) greet

Развертываемое изображение

Участники сообщества NIX, использующих Docker, сделали создание, совместимые с Docker, из производных NIX очень удобными.

Чтобы попробовать это, поместите следующее в файле где -нибудь, скажем, ~/hello.nix Анкет

let
  nixpkgs = import  {};
in
  nixpkgs.dockerTools.buildImage {
    name = "hello-docker-nix";
    tag = "latest";
    contents = [ nixpkgs.hello ];
  }

Затем построите его.

~ $ nix-build hello.nix  

Загрузите результат.

~ $ docker load < result

И наконец запустить это.

~ $ docker run hello-docker-nix:latest hello
Hello, world!

Мы можем поместить нашу посылку на докер, совместимый с изображением аналогичным образом. Поместите следующее в файл с именем release.nix в вашем Haskell-on-heroku Проектный каталог.

{ nixpkgs ? import  {} }:
let
  inherit (nixpkgs)
    callPackage
    dockerTools;

  package = callPackage ./. {};
in
  dockerTools.buildImage {
    name = "haskell-on-heroku";
    tag = "latest";
    contents = [
      package
    ];
  }

Используя CALLPACKAGE Помощник означает, что мы с меньшей вероятностью случайно получим несколько версий набора пакетов NIX. Если это произойдет, наше приложение все равно будет работать нормально, мы просто могли бы получить больше, чем необходимое изображение.

Давайте попробуем построить его и посмотрим, насколько он велик.

~/haskell-on-heroku $ nix-build release.nix 
# ... build output
~/haskell-on-heroku $ docker load < result 
3f5a871dd9ee: Loading layer   38.1MB/38.1MB
Loaded image: haskell-on-heroku:latest

Это около 38,1 мегабайт. Это неплохо.

Теперь я собираюсь сэкономить нам некоторые проблемы и добавить Busybox На нашем изображении, а также убедитесь, что у него есть CMD настроен.

diff --git a/release.nix b/release.nix
index 8fa2527..e14a534 100644
--- a/release.nix
+++ b/release.nix
@@ -3,7 +3,8 @@
 let
   inherit (nixpkgs)
     callPackage
-    dockerTools;
+    dockerTools
+    busybox;

   package = callPackage ./. {};
 in
@@ -12,5 +13,9 @@ in
     tag = "latest";
     contents = [
       package
+      busybox
     ];
+    config = {
+      Cmd = ["/bin/${package.pname}"];
+    };
   }

Нам нужно указать команду, чтобы Heroku знал, как запустить контейнер, который он создаст с нашего изображения. Нам нужно Busybox Потому что Хероку попытается запустить команду нашего изображения с bash -c Анкет Изображения, построенные с Nix’s Dockertools настолько минимальны, что у них нет избиение или даже /bin/sh .

Отправляя его

Теперь у нас есть все, что нам нужно. Последние шаги — создать приложение Heroku, подтолкнуть наше изображение в реестр Heroku и выпустить его.

Во -первых, предполагая, что у вас уже есть учетная запись Heroku, войдите в командную строку Heroku.

~/haskell-on-heroku $ nix run nixpkgs.heroku \
> --command heroku login

Затем также войдите в реестр контейнеров.

~/haskell-on-heroku $ nix run nixpkgs.heroku \
> --command heroku container:login

Далее создайте приложение.

~/haskell-on-heroku $ nix run nixpkgs.heroku \
> --command heroku create

Создайте наше изображение.

~/haskell-on-heroku $ nix-build release.nix

Загрузите его.

~/haskell-on-heroku $ docker load < result

Отметьте его с помощью имени нашего приложения Heroku и типа процесса, который мы хотели бы запустить его.

~/haskell-on-heroku $ docker tag \
> haskell-on-heroku \
> registry.heroku.com/infinite-anchorage-09330/web

Подтолкнуть его в реестр.

~/haskell-on-heroku $ docker push \
> registry.heroku.com/infinite-anchorage-09330/web

И, наконец, выпустите его.

~/haskell-on-heroku $ nix run nixpkgs.heroku \
> heroku container:release -a infinite-anchorage-09330 web

Эй, Престо, наше удивительное приложение теперь будет доступно всему миру. Как круто.

Однако это похоже на то, что нужно помнить, так что мы лучше всего подчеркиваем это как можно больше в сценарии. Сценарий, который мы могли бы позвонить ./развертывать .

#!/usr/bin/env bash

set -exu

app_name=$1
result=$(nix-build --no-out-link release.nix)

docker load < $result
docker tag $app_name registry.heroku.com/$app_name/web
docker push registry.heroku.com/$app_name/web

nix run nixpkgs.heroku --command \
  heroku container:release -a $app_name web

С этим зданием и развертыванием немного более управляемо.

~/haskell-on-heroku $ ./deploy infinite-anchorage-09330

Я подготовил Репозиторий обо всем, через что мы прошли здесь как ссылка. Если повезет, это может помочь кому -то получить свое потрясающее приложение Haskell на безумное пространство, которое является Интернетом.

Оригинал: «https://dev.to/bradparker/using-nix-to-deploy-a-haskell-web-app-to-heroku-57ob»