Создание CloudFoundry/IBM Bluemix buildpack или веб сервис на Awk (gawk)
gawk — глазеть разинув рот, таращить глаза
Дальше никаких шуток, я действительно опишу как запустить Awk (Gawk) веб сервис на IBM Bluemix.
CloudFoundry и созданная на его основе платформа IBM Bluemix поддерживают много разных языков программирования и веб фреймворков. Все это благодаря поддержке билдпаков (мой перевод слова buildpack). Билдпак можно рассматривать как плагин, который отвечает за установку и настройку среды выполнения приложения. Создают билдпак обычно в двух случаях.
Бывает, что язык или фреймворк поддерживается, но для приложения нужны сторонние библиотеки, например OpenCV, которые невозможно поставить стандатрным для этого языка менеджером зависимостей (npm, pip, bundler). В этом случае модифицируется существующий билдпак, в который добавляется установка нужных библиотек. Большинство билдпаков лежат на github, делается форк, с помощью которого можно будет деплоить приложение.
Второй случай более редкий — язык пока не поддерживается, т.е. билдпак пока никто не создал. В этом случае придется сделать его с нуля, что и будет описано чуть ниже. Я долго искал какой язык пока не поддерживается CloudFoundry, выбор пал на Brainfuck. К сожалению, когда я дописал билдпак, я понял, что быстро написать веб сервер на этом языке у меня не получится. Поиск показал, что и у других с этой задачей возникли сложности.
Чтобы было чуть понятнее в чем проблема — билдпак настраивает среду, в которую затем помещается пользовательское приложение, ему через переменные окружения передаются порт и имя хоста, где приложение должно начать обрабатывать HTTP запросы. Т.е. простого hello world мало. Я продолжил поиски и нашел реализацию веб серверов на PostScript и Awk (точнее gawk). В итоге я выбрал Awk и начал писать новый билдпак.
Документация хорошо описывает общие концепции, также можно посмотреть готовые билдпаки. В самом простом случае необходимо создать создать папку bin и поместить в нее 3 исполнимых файла:
detect — определяет можно ли применять данный билдпак к приложению. Если да, то скрипт должен вернуть 0 и напечатать имя языка или фреймворка. В нашем случае мы проверяем наличие app.awk в корне приложения, введем такое соглашение.
#!/usr/bin/env bash
# bin/detect
# Any awk web app must have app.awk file
if [ -f $1/app.awk ]; then
echo "gawk"
exit 0
fi
exit 1
compile должен устновить все что нужно и скомпилировать пользовательское приложение, если это требуется. В нашем случае надо загрузить и установить gawk. Чтобы экономить время во время разворачивания приложения можно было собрать его вручную под разные версии Ubuntu и выбирать подходящую на этом шаге. Но сборка gawk не такой затратный процесс, кроме того, поддерживается кэш, так что для большинства проектов компиляция будет выполняться один раз. Зато мы точно получим файл, собранный под нужную версию ОС и архитектуру.
#!/usr/bin/env bash
# bin/compile
set -e
build_dir=$1
cache_dir=$2
awk_cache=$cache_dir/gawk-4.1.3
awk_url="http://ftp.gnu.org/gnu/gawk/gawk-4.1.3.tar.gz"
if [ -f $awk_cache/gawk ]; then
echo "Using cached gawk"
else
# download and compile gawk
mkdir -p $awk_cache
curl -o $cache_dir/gawk.tar.gz "$awk_url"
cd $cache_dir
tar zxvf gawk.tar.gz
cd $awk_cache
./configure
make
fi
# copy gawk to build dir
cp $awk_cache/gawk $build_dir
# set path and test gawk
PATH=$build_dir:$PATH
gawk -V
# create a launcher to wrap env vars passing
echo "#!/usr/bin/env bash\n" > $build_dir/awk-start
echo "/app/gawk -v PORT=\"\$PORT\" -v HOST=\"\$VCAP_APP_HOST\" -f \$1" >> $build_dir/awk-start
chmod +x $build_dir/awk-start
Первый аргумент — место сборки файлов (build_dir), второй — кэш. Наша задача положить нужные для запуска файлы в build_dir, в нашем случает это gawk. Кроме того, Awk скрипт не имеет доступа к переменным окружения, а нам нужно знать какой порт нам выделяет CloudFoundry для запуска (переменная окружения PORT). Поэтому я сделал небольшую обертку для удобного запуска.
release — передает метаданные, необходимые для запуска приложения. Обычно это переменные окружения и строка запуска по умолчанию. Она будет использоваться, если приложение не предоставляет этой информации, что обычно делается в файле Procfile.
#!/usr/bin/env bash
# bin/release
cat <
Проверяем работу скриптов локально, потом выкладываем все на github, запоминаем адрес https://github.com/hashmap/gawk-buildpack
Теперь пишем приложение. Создаем папку gawktest, в ней файл app.awk
# A Web Server in Awk
# a simple, single user, web server built with gawk.
# based on code form http://awk.info/?tools/server by Michael Sanders
BEGIN {
host = "/inet/tcp/" PORT "/0/0" # host string
status = 200 # 200 == OK
reason = "OK" # server response
RS = ORS = "\r\n" # header line terminators
doc = Setup() # html document
len = length(doc) + length(ORS) # length of document
print "Staring AWK server"
while (1) {
print "HTTP/1.0", status, reason |& host
print "Connection: Close" |& host
print "Pragma: no-cache" |& host
print "Content-length:", len |& host
print ORS doc |& host
close(host) # close client connection
host |& getline # wait for new client request
}
}
function Setup() {
tmp = "\
Simple gawk server \
\
Hello from awk!\
\
"
return tmp
}
Проверяем работу приложения локально:
gawk -v PORT=8080 -f app.awk
теперь можно отправлять на Bluemix, делаем стандартный cf push, но еще указываем адрес нашего билдпака:
gawktest cf push gawktest -b https://github.com/hashmap/gawk-buildpack
Updating app gawktest in org xxx@gmail.com / space dev as xxx@gmail.com...
OK
Uploading gawktest...
Uploading app files from: /Users/alex/projects/gawktest
Uploading 32.3K, 3 files
Done uploading
OK
Stopping app gawktest in org xxx@gmail.com / space dev as xxx@gmail.com...
OK
Starting app gawktest in org xxx@gmail.com / space dev as xxx@gmail.com...
-----> Downloaded app package (8.0K)
-----> Downloaded app buildpack cache (11M)
Cloning into '/tmp/buildpacks/gawk-buildpack'...
Using cached gawk
GNU Awk 4.1.3, API: 1.1
Copyright (C) 1989, 1991-2015 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
-----> Uploading droplet (724K)
1 of 1 instances running
App started
OK
App gawktest was started using this command `/app/awk-start app.awk`
Showing health and status for app gawktest in org xxx@gmail.com / space dev as xxx@gmail.com...
OK
requested state: started
instances: 1/1
usage: 64M x 1 instances
urls: gawktest.mybluemix.net
last uploaded: Wed Jul 15 12:21:13 UTC 2015
stack: lucid64
buildpack: https://github.com/hashmap/gawk-buildpack
state since cpu memory disk details
#0 running 2015-07-15 03:22:08 PM 0.0% 1.1M of 64M 1.9M of 1G
Все работает и доступно, пока по крайней мере, не забывайте, что сервер однопользовательский. Т.к. это не первый запуск, то уже собранный gawk просто скопировался из кэша. При первом запуске нового приложения можно будет увидеть как он скачивается, распаковывается и собирается. Также для отладки печатается версия gawk и его лицензия.
Если кто напишет веб фреймворк на Brainfuck — дайте знать.