Showing posts with label buildpack. Show all posts
Showing posts with label buildpack. Show all posts

Cloud Foundry Buildpacks


A buildpack provides framework and run time support for applications. Buildpacks examine user-provided artifacts to determine what dependencies to download and how to configure applications to communicate with different services.

When we push an application, Cloud Foundry automatically detects which buildpack is required and installs it on the Droplet Execution Agent where the application needs to run.

There are three elements of a buildpack. They are detect, compile and release. 

Detect

A script to detect condition to run buildpack. Runs this detect script against deployed application. OK if exit 0. To get an idea, let's look into the detect script of ruby buildpack.
#!/bin/bash
if [ -f "$1/Gemfile" ]; then
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" echo "ruby $(cat $SCRIPT_DIR/../VERSION)" exit 0 else echo "no" exit 1 fi
If we analyse the script, what it does simply is doing a conditional check to see if there is a Gemfile. If so, ruby buildpack is used since the application is confirmed by the 'detect' script.
Detect can be written in ruby or bash.

There are some examples that detect itself is written in bash and then calls python script. cf-php buildpack is similar to that.

#!/bin/bash
BP=$(dirname $(dirname $0)) export PYTHONPATH=$BP/lib VERSION=`cat $BP/VERSION` python $BP/scripts/detect.py $1 $VERSION


Compile

This is the key script to setup language or framework runtime setup. 
What this does is, it downloads execution environment sources and then compiles. 
Because it takes time to do compile, many buildpacks download pre-compiled binaries.  


Release

A script to return metadata required for execution in yaml format.
#!/usr/bin/env  ruby require 'pathname'  release = Pathname.new(ARGV.first).join("tmp/heroku-buildpack-release-step.yml") puts release.read if release.exist?

Staging

Staging refers to building the droplet, which is the executable bundle of application. At this time, user deploys the application, process the application by buildpack description and then create the droplet. Let me describe this graphically. 



1. When user gives the command 'cf push', user uploads the application to Cloud Controller. 

2. Cloud controller sends the 'staging.start' message to DEA to request staging activity. 

3. DEA does staging and build the droplet.

4. Once droplet is built, it returns back to cloud controller. 



The above diagram explains the complete scenario.

Admin buildpack

This is a buildpack which is directly installed in Cloud Foundry. Suppose that user did not specify a buildpack. Then Cloud Foundry selects the appropriate buildpack from the admin buildpack. Administrator can add using create-buildpack. Cloud Foundry service provider can add supported languages to the platform.

Staging.start is received by DEA.


Download application from Cloud Controller.

Execute admin buildpack detect based on priorities.


Run buildpack compile which matched.



Download Ruby binaries, setup binaries, execute 'bundle install', replace database.yml(in case of rails) etc.

Execute release and produce necessary information.



Droplet contents.


In case of a Ruby app, the droplet produced consists ruby executable created by the buildpack, uploaded application, files installed by bundle install and start command description. 

System Buildpacks

This table describes Cloud Foundry system buildpacks. Each buildpack row lists supported languages and frameworks and includes a GitHub repo link. Specific buildpack names also link to additional documentation.

NameOther Supported Languages and FrameworksGitHub Repo
Java
Grails, Play, Spring, or any other JVM-based language or framework
Java source
Ruby
Ruby, Rack, Rails, or Sinatra
Ruby source
Node.js
Node or JavaScript
Node.js source
Binary
NA
Binary source
Go
NA
Go source
PHP
NA
PHP source
Python
NA
Python source
Staticfile
HTML, CSS, or JavaScript
Staticfile source


Other Buildpacks

If a certain application uses a language or framework that Cloud Foundry buildpacks do not support, we can try the following ways.

1. Customize an existing buildpack, or create your own custom buildpack.

For example, by default Cloud Foundry does not support Haskell. Using a buildpack for Haskell allows us to add support for it at the deployment stage. When we push an application written using Haskell, the required buildpack is automatically installed on the Cloud Foundry Droplet Execution Agent (DEA) where the application will run.

A common development practice for custom buildpacks is to fork existing buildpacks and sync subsequent patches from upstream.

2. Use a Cloud Foundry Community Buildpack.


Heroku maintains a collection of officially supported buildpacks but there are also third-party buildpacks that enable us to use languages and frameworks beyond those that are officially supported by Heroku.

Custom buildpack

User can specify the buildpack at the time of deployment. This is called custom buildpack. When custom buildpack is specified,  detect step is skipped, compile step is executed. 

Binary buildpack

This is a special buildpack that I came across. This is a Cloud Foundry buildpack for running arbitrary binary web servers.

Unlike most other Cloud Foundry buildpacks, the binary buildpack must be specified in order for it to be used in staging your binary file. You can specify the buildpack your app should use with the -b option for cf push as follows.

cf push my_app -b https://github.com/cloudfoundry/binary-buildpack.git

There are two ways to provide Cloud Foundry with the shell command to execute your binary.
1. Procfile
Include in your app's root directory a Procfile that specifies a web task. Eg: web: ./app

2. Command line
Alternatively, you can provide the start command when deploying your app with cf push by including a -c option:
cf push my_app -c './app' -b binary-buildpack

Container to run application

Warden

Warden is a container to isolate user application. User application runs inside Warden container. When the application stops, then the container gets destroyed. 

Currently, in addition to run the application, staging process itself and also used to run component in Bosh-lite environment. 



dea_next uses Warden Client to invoke Warden Server API. Communication between Warden is determined by Warden protocol. Warden Server is written in Ruby and and the container which Warden Server runs is written in C.


Why Warden(vs Docker)

  • Docker only runs a single process, it does not conform Cloud Foundry architecture. 
  • Cannot control limit after the container creation.
  • Cannot control disk and bandwidth limits.
The main purpose is ultimately the same in Docker and Cloud Foundry.  



cf Command Line Interface Setup in Ubuntu


Cloud Foundry CLI is the official command line client for Cloud Foundry. In this blog post, I will show you on how to deploy an application in Cloud Foundry using this tool. It is very easy to use this CLI once it is correctly installed and set up.

In order to log into cf, you need to create an account in run.pivotal.io. You can sign up for free for 60 day free trial which requires no credit card. Please Remember the credentials, because you need them later to login to cf.

Getting started

Latest stable

Download and run the installer for your platform from here. You can find the installer or compressed binary for your platform from there. 

Command line

If you prefer installing cf cli via command line, Ubuntu users can use the following command. 

$ curl -L "https://cli.run.pivotal.io/stable?release=linux64-binary&source=github" | tar -zx


Log in

Once installed, you can log in to cloud foundry using cf cli.
$ cf login
API endpoint: https://api.run.pivotal.io
Email> nanduni@wso2.com
Password> 
Authenticating...
OK
Targeted org nanduni-org
Targeted space development
                   
API endpoint:   https://api.run.pivotal.io (API version: 2.48.0)   
User:           nanduni@wso2.com   
Org:            nanduni-org   
Space:          development 
If you are using cf for the first time, this will ask you to create organizations, spaces required etc.


Push an application

Now, go to the base directory that contains your application and execute the following command.
$ cf push mytomcat
Creating app mytomcat in org nanduni-org / space development as nanduni@wso2.com...
OK
Creating route mytomcat.cfapps.io...
OK
Binding mytomcat.cfapps.io to mytomcat...
OK
Uploading mytomcat...
Uploading app files from: /home/nanduni/apache-tomcat-7.0.67/webapps/Servlet3
Uploading 3.2K, 7 files
Done uploading               
OK
Starting app mytomcat in org nanduni-org / space development as nanduni@wso2.com...
Downloading go_buildpack...
Downloading java_buildpack...
Downloading ruby_buildpack...
Downloading python_buildpack...
Downloading nodejs_buildpack...
Downloading staticfile_buildpack...
Downloading php_buildpack...
Downloading liberty_buildpack...
Downloading binary_buildpack...
Downloaded binary_buildpack
Downloaded php_buildpack
Downloaded java_buildpack
Downloaded ruby_buildpack
Downloaded liberty_buildpack
Downloaded python_buildpack
Downloaded nodejs_buildpack
Downloaded go_buildpack
Downloaded staticfile_buildpack
Creating container
Successfully created container
Downloading app package...
Downloaded app package (2.3K)
Staging...
-----> Java Buildpack Version: v3.5.1 | http://github.com/pivotal-cf/pcf-java-buildpack.git#d6c19f8
-----> Downloading Open Jdk JRE 1.8.0_65 from https://download.run.pivotal.io/openjdk/trusty/x86_64/openjdk-1.8.0_65.tar.gz (1.1s)
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.0s)
-----> Downloading Open JDK Like Memory Calculator 2.0.1_RELEASE from https://download.run.pivotal.io/memory-calculator/trusty/x86_64/memory-calculator-2.0.1_RELEASE.tar.gz (0.0s)
       Memory Settings: -Xss1M -Xmx768M -XX:MaxMetaspaceSize=104857K -Xms768M -XX:MetaspaceSize=104857K
-----> Downloading Tomcat Instance 8.0.30 from https://download.run.pivotal.io/tomcat/tomcat-8.0.30.tar.gz (0.3s)
       Expanding Tomcat Instance to .java-buildpack/tomcat (0.1s)
-----> Downloading Tomcat Lifecycle Support 2.5.0_RELEASE from https://download.run.pivotal.io/tomcat-lifecycle-support/tomcat-lifecycle-support-2.5.0_RELEASE.jar (0.0s)
-----> Downloading Tomcat Logging Support 2.5.0_RELEASE from https://download.run.pivotal.io/tomcat-logging-support/tomcat-logging-support-2.5.0_RELEASE.jar (0.0s)
-----> Downloading Tomcat Access Logging Support 2.5.0_RELEASE from https://download.run.pivotal.io/tomcat-access-logging-support/tomcat-access-logging-support-2.5.0_RELEASE.jar (0.0s)
Exit status 0
Staging complete
Uploading droplet, build artifacts cache...
Uploading droplet...
Uploading build artifacts cache...
Uploaded build artifacts cache (52.3M)
Uploaded droplet (51.1M)
Uploading complete
1 of 1 instances running
App started
OK
App mytomcat was started using this command `CALCULATED_MEMORY=$($PWD/.java-buildpack/open_jdk_jre/bin/java-buildpack-memory-calculator-2.0.1_RELEASE -memorySizes=metaspace:64m.. -memoryWeights=heap:75,metaspace:10,native:10,stack:5 -memoryInitials=heap:100%,metaspace:100% -totMemory=$MEMORY_LIMIT) &&  JAVA_HOME=$PWD/.java-buildpack/open_jdk_jre JAVA_OPTS="-Djava.io.tmpdir=$TMPDIR -XX:OnOutOfMemoryError=$PWD/.java-buildpack/open_jdk_jre/bin/killjava.sh $CALCULATED_MEMORY -Daccess.logging.enabled=false -Dhttp.port=$PORT" exec $PWD/.java-buildpack/tomcat/bin/catalina.sh run`
Showing health and status for app mytomcat in org nanduni-org / space development as nanduni@wso2.com...
OK
requested state: started
instances: 1/1
usage: 1G x 1 instances
urls: mytomcat.cfapps.io
last uploaded: Wed Jan 27 05:54:32 UTC 2016
stack: cflinuxfs2
buildpack: java-buildpack=v3.5.1-http://github.com/pivotal-cf/pcf-java-buildpack.git#d6c19f8 open-jdk-like-jre=1.8.0_65 open-jdk-like-memory-calculator=2.0.1_RELEASE tomcat-access-logging-support=2.5.0_RELEASE tomcat-instance=8.0.30 tomcat-lifecycle-support=2.5.0...
     state     since                    cpu    memory          disk  details   
#0   running   2016-01-27 11:25:10 AM   0.0%   109.2M of 1G   129.5M of 1G      

When you push an app, Cloud Foundry determines which buildpack to use. Each buildpack has a position in the detection priority list. Cloud Foundry first checks whether the buildpack in position 1 is right for the app. If the position 1 buildpack is not appropriate, Cloud Foundry moves on to the position 2 buildpack. This goes on until Cloud Foundry finds the correct buildpack.

I no matching buildpack is found, cf push fails with an error like below.

Staging...
None of the buildpacks detected a compatible application
Exit status 222
Staging failed: Exited with status 222
FAILED
NoAppDetectedError

The available buildpacks can be checked using the following command.

$ cf buildpacks
Getting buildpacks...
buildpack              position   enabled   locked   filename   
staticfile_buildpack   1          true      false    staticfile_buildpack-cached-v1.3.0.zip   
java_buildpack         2          true      false    java-buildpack-v3.5.1.zip   
ruby_buildpack         3          true      false    ruby_buildpack-cached-v1.6.12.zip   
nodejs_buildpack       4          true      false    nodejs_buildpack-cached-v1.5.5.zip   
go_buildpack           5          true      false    go_buildpack-cached-v1.7.2.zip   
python_buildpack       6          true      false    python_buildpack-cached-v1.5.4.zip   
php_buildpack          7          true      false    php_buildpack-cached-v4.3.3.zip   
liberty_buildpack      8          true      false    liberty_buildpack.zip   
binary_buildpack       9          true      false    binary_buildpack-cached-v1.0.1.zip   

I hope that this blog post would be useful for anyone who is interested in deploying applications in cloud foundry using cf cli.