een lange titel

Een Wt voorbeeld in Docker

Wt werkt ook in een Docker container.

Dit is een voorbeeld dat ook al in een vorig bericht gepresenteerd is. Het is een simpel C++ Wt voorbeeld dat een veelhoek tekent in een canvas. Door gebruik te maken van Docker wordt getoond dat ook C++ geschikt is om webapplicaties te ontwerpen. Door de applicatie binnen een Docker container te starten heb je de werkomgeving voor de applicatie zelf in de hand. We laten Docker zelf de C++ compilatie uitvoeren zodat de applicatie als een gewoon programma kan gestart worden. In tegenstelling tot Java of Erlang heb je geen runtime nodig.

Het project bestaat uit een beperkt aantal bestanden en is zo gestructureerd:

.
|-- Dockerfile
|-- Makefile
`-- veelhoek
    |-- CMakeLists.txt
    `-- veelhoek.cpp

Dit zijn de bestanden:

  • De Dockerfile beschrijft hoe de Docker image kan gebouwd worden.
  • De Makefile geeft aan welke docker commando’s je moet beheersen voor dit project.
  • De C++ broncode staat in veelhoek.cpp.
  • Het tekstbestand CMakeLists geeft aan hoe de applicatie kan gebouwd worden met cmake.

Dit is de broncode van de webapp:

#include <Wt/WApplication>
#include <Wt/WContainerWidget>
#include <Wt/WPaintDevice>
#include <Wt/WPaintedWidget>
#include <Wt/WPainter>

#include <Wt/WBrush>
#include <Wt/WColor>
#include <Wt/WPen>
#include <Wt/WPointF>

class VeelhoekWidget : public Wt::WPaintedWidget
{
public:
   VeelhoekWidget(Wt::WContainerWidget *parent = 0)
	   : Wt::WPaintedWidget(parent)
   {
      resize(600, 100);   // Provide a default size.

      /*
         Kies voor SVG, canvas of een png afbeelding
       */
      //setPreferredMethod(InlineSvgVml);
      //setPreferredMethod(HtmlCanvas);
      setPreferredMethod(PngImage);
   }

protected:
   void paintEvent(Wt::WPaintDevice *paintDevice)
   {
      Wt::WPainter painter(paintDevice);
      painter.setBrush(Wt::WBrush(Wt::WBrush(Wt::blue)));
      painter.setPen(Wt::red);

	   // Teken een driehoek.
      const Wt::WPointF points[] =  
      {
         Wt::WPointF(10, 10), 
         Wt::WPointF(100, 10),
         Wt::WPointF(100, 100) 
      };
      painter.drawPolygon(points, 3);
   }

private:
};


class VeelhoekApplication : public Wt::WApplication
{
public:
   VeelhoekApplication(const Wt::WEnvironment& env);

private:
};

VeelhoekApplication::VeelhoekApplication(const Wt::WEnvironment& env)
  : Wt::WApplication(env)
{
   setTitle("Veelhoek");

   Wt::WContainerWidget *container = new Wt::WContainerWidget();
   VeelhoekWidget *painting = new VeelhoekWidget(container);
   
   root()->addWidget(container);
}

Wt::WApplication *createApplication(const Wt::WEnvironment& env)
{
   return new VeelhoekApplication(env);
}

int main(int argc, char **argv)
{
   return Wt::WRun(argc, argv, &createApplication);
}

De broncode hebben we al gezien in een ander bericht en wordt hier niet verder uitgelegd. Om het project te compileren met cmake is deze beschrijving nodig:

INCLUDE_DIRECTORIES(/usr/local/wt/include)
#LINK_DIRECTORIES(/usr/local/lib)

ADD_EXECUTABLE(veelhoek
veelhoek.cpp
)

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")

# For FastCGI deployment:
##TARGET_LINK_LIBRARIES(myprog.wt
##wtfcgi wt someotherlib
##)

# Or, for built-in httpd deployment:
TARGET_LINK_LIBRARIES(veelhoek
  wthttp wt pthread
)

Met deze Dockerfile kan je een Docker image maken waarin een Wt webapplicatie draait.

FROM ubuntu:14.04
MAINTAINER Leo Rutten "leo.rutten@kuleuven.be"
RUN apt-get update
RUN apt-get install -y witty witty-dev witty-doc witty-dbg witty-examples
RUN apt-get install -y build-essential
RUN apt-get install -y cmake
RUN mkdir /veelhoek
COPY veelhoek/ /veelhoek
WORKDIR /veelhoek
RUN cmake .
RUN make
CMD ["/veelhoek/veelhoek", "--http-address=0.0.0.0", "--http-port=80", "--docroot=/veelhoek"]
EXPOSE 80

De Dockerfile bestaat uit een aantal stappen die één voor één uitgevoerd worden bij het aanmaken van de image. Als basis voor de image wordt ubuntu:14.04 gebruikt.

FROM ubuntu:14.04

Vervolgens worden met apt-get de nodige pakketten geïnstalleerd. De eerste install doet een aantal witty installaties. Dit is Wt die geïnstalleerd wordt.

RUN apt-get update
RUN apt-get install -y witty witty-dev witty-doc witty-dbg witty-examples

Met build-essental worden de g++ compiler en andere tools geïnstalleerd En cmake hebben we ook nodig.

RUN apt-get install -y build-essential
RUN apt-get install -y cmake

Het eerste Docker commando bouwt de image:

docker build -t wt/wt-veelhoek .

Dit commando leest de Dockerfile en voert alle commando’s uit. Met volgende commando kan de container gestart worden.

docker run -d --name veelhoek -p 80:80 wt/wt-veelhoek

De container draait in de achtergrond als een daemon, vandaar de -d optie. De container krijgt ook een naam met --name veelhoek. Vermits de webapp in de container op poort 80 wacht, maken we deze poort ook toegankelijk van buiten de container. Dit betekent dat met localhost in de browser de veelhoek getoond wordt.

Je kan nagaan of de container draait:

$ docker ps -a
CONTAINER ID  IMAGE           COMMAND                CREATED       STATUS       PORTS                NAMES
7dd202afb4b6  wt/wt-veelhoek  "/veelhoek/veelhoek -" 2 seconds ago Up 1 seconds 127.0.0.1:80->80/tcp veelhoek

Vermits de container in de achtergrond draait, is de consoleout niet meteen zichtbaar. Je kan die zo bekijken:

docker logs veelhoek

Het stopzetten gebeurt zo:

docker stop veelhoek

En tot slot kan je de container na gebruik verwijderen.

docker rm veelhoek

De volgende Makefile is handig om alle commando’s te onthouden.

build:
        docker build -t wt/wt-veelhoek .

run:
        docker run -d --name veelhoek -p 80:80 wt/wt-veelhoek

runbash:
        docker run -ti --name veelhoek wt/wt-veelhoek /bin/bash

bash:
        docker exec -ti veelhoek /bin/bash

stop:
        docker stop veelhoek

logs:
        docker logs veelhoek
ps:
        docker ps -a

rm:
        docker rm veelhoek

Er zijn hierboven nog twee doelen die nog een verklaring vragen.

  • make runbash start de container zonder de webapp te starten. Je start dan wel bash in de plaats. Hiermee kan je de container manueel controleren.
  • make bash start bash bij een container waarin de webapp gestart is. Zo kan je de webapp controleren.

Een volgende stap bij dit voorbeeld is de uitbating bij een cloudprovider. En dat is voor een volgend bericht.