Giter VIP home page Giter VIP logo

php-ci's Introduction

PHP-CI for Yii

This sets up a full Continuous Integration environment for PHP projects with the Yii Framework based on Debian-based servers.

About

When you are working on serious projects you want to introduce Continuous Integration into your development routine. Unfortunately it is quite intimidating to set up a full environment and get started if you have never done it before.

There is an excellent intro at jenkins-php.org, so this forms the basis of the CI environment set up by these scripts.

The magic behind the scenes is powered by Ansible, a powerful yet simple way to manage servers. It requires only Python on the management machine, SSH access, and some knowledge of YAML, if you wish to adjust the installation yourself.

There are two ways how to perform the installation for PHP-CI

  1. fully automated (fast and simple) - just download a file and execute it
  2. executing Ansible playbooks (advanced)

Disclaimer

Please do not run any of these scripts on production servers or machines directly accesible from the internet unless you know what you are doing. These scripts will not secure your installation and expose your systems to the world. Yes, even your source code will be accessible to anyone!

Best to run it on a machine behind a firewall that cannot be accessed from the outside.

Requirements

In the following we assume you have at least one Debian machine, preferably running Debian Wheezy (7).

Set up a Debian machine with a minimal installation. Use the official documentation, if needed. All the testing was performed on a minimal install of Debian 7.3.0 AMD64 as well as Ubuntu Server 12.04 but it should work on any Debian system. It might also work on already pre-configured machines.

All required software will be taken care of by the install.sh script.

It helps to have some familiarity with the linux command line. Otherwise just don't be afraid and let the scripts do the heavy lifting.

Simple setup

Copy the file install.sh to your Debian/Ubuntu machine. Log into your machine that is going to be the PHP server and start the deployment with the following commands

$ wget https://raw.github.com/yauh/php-ci/master/install.sh
$ sudo /bin/bash install.sh

The script asks you to enter the port where the Jenkins CI instance is supposed to listen on. The default is 8080. You may set it to anything else, but not 80 as that is already used by the Apache that comes with the automated installation. Then you must provide your user password that enables the connection.

Now sit back and wait a while, the script first bootstraps Ansible on your machine and then installs a LAMP stack plus the Jenkins-CI with a template for PHP projects (optimized slightly for use with Yii).

Also you can watch me perform a simple setup on Youtube. (Beware, the video is a bit outdated even though the principle is still the same!)

Advanced setup

Cloning into php-ci

Since the individual roles are used as submodules make sure you check them out correctly, e.g. like this:

$ git clone https://github.com/yauh/php-ci.git
$ cd php-ci
$ git submodule init && git submodule update

Using the playbooks

If you prefer to know what you're doing and are familiar with the linux shell and perhaps even Ansible, let's have a deeper look.

We'll only use Ansible playbooks, no need to use the shell script (install.sh). But still, the setup is not optimized for security but rather to get you up and running as quickly as possible.

Ansible uses playbooks to perform tasks. These may be parameterized in that some tasks are only performed on dedicated LAMP servers, others only on CI machines. You organize all your machines in the playbooks/hosts/ci-hosts file. You may use IPs or hostnames.

For all tasks carried out there are some switches you can adjust - the variables. You can specifically set variables inside a role or override it for a specific host or a group of hosts (check playbooks/group_vars/all).

We assume the following setup for the next steps:

  • Management Machine: MacBook
  • Management User: stephan
  • Remote Server CI: 192.168.1.1
  • Remote Server LAMP: 192.168.1.2

Generate ssh keys on your management machine

macbook: stephan$ ssh-keygen -t rsa

Install Ansible

Install Ansible on your management machine according to the installation documentation. If you must run it on Windows you can do so using Cygwin although it is not officially supported.

On Mac OS X you should use homebrew.

macbook: stephan$ ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
macbook: stephan$ brew install ansible

Define your environment

In order for the playbooks to work you need to define which machines to run on. There are two types of server: CI and LAMP. Both can run on the same machine if you wish, but you can also separate them if you want.

Go to playbooks/hosts/ci-hosts and adjust the hostnames or IP addresses for the machines where you want to perform the deployment.

Set up ssh connection to remote machines

Setting up the remote machine so you can easily log in using ssh is done using the init playbook. It will

  • set up a user and password as defined in the vars section in init.yml (create a password on the shell using $ openssl passwd -salt <salt> -1 <plaintext>)
  • copy your ssh key to the remote machine so you can connect without a password through ssh
  • refresh your packages and install some basic software
  • enables sudo without a password for your newly created user

Make sure you can connect to the remote machine using ssh like this (the init must be performed as root or with sudo powers):

macbook: stephan$ ssh [email protected] cat /etc/hostname

Go to the root of the php-ci project and execute the playbook like this

macbook: stephan$ ansible-playbook playbooks/init.yml -i playbooks/hosts/ci-hosts -k

On Mac OS X you need to make sure that sshpass is installed. Assuming you use homebrew you can install it like this:

macbook: stephan$ brew install https://raw.github.com/eugeneoden/homebrew/eca9de1/Library/Formula/sshpass.rb

Check if it works (if you changed myuser in the vars section to something else, adjust the command accordingly):

macbook: stephan$ ssh [email protected]

Change the entry for bootstrap_user in the file playbooks/group_vars/all to myuser (or the name you provided in the init stage).

Set up CI environment

Executing Playbooks

Ready to bootstrap - you can now execute the bootstrap.yml playbook:

macbook: stephan$ ansible-playbook playbooks/bootstrap.yml -i playbooks/hosts/ci-hosts

Individual steps (read: roles) can be (de-)activated by explicitly calling certain tags using the --tags="<tagname>" switch. Only those mentioned will be executed then.

Roles

role-common

  • Typical tasks to be performed on any server
  • can be invoked separately using the --tags="common" attribute to the playbook command

role-msmtp

  • If you already have a mail server and want to use it with SMTP (e.g. GMail or iCloud) instead of a full blown mail server use this. Then Jenkins can also send you mails.
  • can be invoked separately using the --tags="mail" attribute to the playbook command

role-jenkins-php

  • Deploys Jenkins CI with required PHP tools as pear modules
  • It also sets up a demonstration job using the yii framework
  • can be invoked separately using the --tags="php-ci" attribute to the playbook command

role-lamp

  • Deploys a LAMP stack with Apache2 and MySQL and sets up a first site on port 80
  • can be invoked separately using the --tags="lamp" attribute

role-hardening

  • Tasks that will make your server more secure. Only execute these if you know what you are doing.
  • can be invoked separately using the --tags="hardening" attribute to the playbook command

Known Issues

Sometimes during the execution of role-jenkins-php the last step - triggering a build for the example project - will fail. This has no effect on your setup, it just means you need to start the first build manually.

Unless you provide proper credentials for your SMTP server, role-msmtp will always fail.

Changelog

2014-01-25 - v0.0.3 Restructured project to use roles as submodules

2014-01-24 - v0.0.2 Massive Ansible and install.sh cleanup. Now with Ubuntu support

2014-01-23 - v0.0.1 Initial release with support for Debian only

php-ci's People

Contributors

yauh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

php-ci's Issues

install fails

TASK: [role-lamp | Update apt cache] ******************************************
failed: [127.0.0.1] => {"failed": true, "parsed": false}
SUDO-SUCCESS-ljkdaixgcgngyucyvlyxvosyfwranbrd
Traceback (most recent call last):
File "/tmp/ansible-tmp-1418104543.83-147288450818790/apt", line 2167, in
main()
File "/tmp/ansible-tmp-1418104543.83-147288450818790/apt", line 547, in main
cache.update()
File "/usr/lib/python2.7/dist-packages/apt/cache.py", line 440, in update
raise FetchFailedException(e)
apt.cache.FetchFailedException: W:Failed to fetch http://de.archive.ubuntu.com/ubuntu/dists/trusty-updates/main/binary-amd64/Packages Hash Sum mismatch
, E:Some index files failed to download. They have been ignored, or old ones used instead.

FATAL: all hosts have already failed -- aborting

ubuntu 14.04

Special characters in password fail

Just a note to say that if you have special characters in your password like ()* etc then the install script fails, i presume this is because the shell is expanding the characters.
It cant do the ssh check or the sudo check, never tried any further than there.

Failing to run unit tests

I tried using ansible to make this work. Had a few edits but I finally got it running. I now run into this error as it tries to build the sample project.

Any Ideas?

phpunit:
    [exec] PHP Warning:  require_once(PHPUnit/Runner/Version.php): failed to open stream: No such file or directory in /var/www/yii-1.1.14.f0fee9/framework/test/CTestCase.php on line 11
    [exec] PHP Stack trace:
    [exec] PHP   1. {main}() /usr/bin/phpunit:0
    [exec] PHP   2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:583
    [exec] PHP   3. PHPUnit_TextUI_Command->run() phar:///usr/bin/phpunit/phpunit/TextUI/Command.php:132
    [exec] PHP   4. PHPUnit_Runner_BaseTestRunner->getTest() phar:///usr/bin/phpunit/phpunit/TextUI/Command.php:153
    [exec] PHP   5. PHPUnit_Framework_TestSuite->addTestFiles() phar:///usr/bin/phpunit/phpunit/Runner/BaseTestRunner.php:97
    [exec] PHP   6. PHPUnit_Framework_TestSuite->addTestFile() phar:///usr/bin/phpunit/phpunit/Framework/TestSuite.php:411
    [exec] PHP   7. PHPUnit_Util_Fileloader::checkAndLoad() phar:///usr/bin/phpunit/phpunit/Framework/TestSuite.php:358
    [exec] PHP   8. PHPUnit_Util_Fileloader::load() phar:///usr/bin/phpunit/phpunit/Util/Fileloader.php:77
    [exec] PHP   9. include_once() phar:///usr/bin/phpunit/phpunit/Util/Fileloader.php:93
    [exec] PHP  10. YiiBase::autoload() /var/www/yii-1.1.14.f0fee9/framework/YiiBase.php:0
    [exec] PHP  11. include() /var/www/yii-1.1.14.f0fee9/framework/YiiBase.php:401
    [exec] PHP Fatal error:  require_once(): Failed opening required 'PHPUnit/Runner/Version.php' (include_path='.:/var/lib/jenkins/jobs/yii-sample-project/workspace/src/protected/components:/var/lib/jenkins/jobs/yii-sample-project/workspace/src/protected/models:/usr/share/php:/usr/share/pear') in /var/www/yii-1.1.14.f0fee9/framework/test/CTestCase.php on line 11
    [exec] PHP Stack trace:
    [exec] PHP   1. {main}() /usr/bin/phpunit:0
    [exec] PHP   2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:583
    [exec] PHP   3. PHPUnit_TextUI_Command->run() phar:///usr/bin/phpunit/phpunit/TextUI/Command.php:132
    [exec] PHP   4. PHPUnit_Runner_BaseTestRunner->getTest() phar:///usr/bin/phpunit/phpunit/TextUI/Command.php:153
    [exec] PHP   5. PHPUnit_Framework_TestSuite->addTestFiles() phar:///usr/bin/phpunit/phpunit/Runner/BaseTestRunner.php:97
    [exec] PHP   6. PHPUnit_Framework_TestSuite->addTestFile() phar:///usr/bin/phpunit/phpunit/Framework/TestSuite.php:411
    [exec] PHP   7. PHPUnit_Util_Fileloader::checkAndLoad() phar:///usr/bin/phpunit/phpunit/Framework/TestSuite.php:358
    [exec] PHP   8. PHPUnit_Util_Fileloader::load() phar:///usr/bin/phpunit/phpunit/Util/Fileloader.php:77
    [exec] PHP   9. include_once() phar:///usr/bin/phpunit/phpunit/Util/Fileloader.php:93
    [exec] PHP  10. YiiBase::autoload() /var/www/yii-1.1.14.f0fee9/framework/YiiBase.php:0
    [exec] PHP  11. include() /var/www/yii-1.1.14.f0fee9/framework/YiiBase.php:401

no package matching libapache2-mod-php5

Your package is asking for a package that does not exist or is renamed.
TASK [role-lamp : Install webstack and database] ******************************************************************************************
[DEPRECATION WARNING]: Invoking "apt" only once while using a loop via squash_actions is deprecated. Instead of using a loop to supply
multiple items and specifying pkg: "{{ item }}", please use pkg: ['apache2', 'libapache2-mod-php5', 'mysql-client', 'mysql-server', 'php5', 'php5-cli', 'php5-common', 'php5-curl', 'php5-dev', 'php5-gd', 'php5-gmp', 'php5-mcrypt', 'php5-memcache', 'php5-mysql', 'php5-xsl', 'php-apc', 'php-pear', 'python-mysqldb'] and remove the loop. This feature will be removed in version 2.11. Deprecation
warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
failed: [127.0.0.1] (item=[u'apache2', u'libapache2-mod-php5', u'mysql-client', u'mysql-server', u'php5', u'php5-cli', u'php5-common', u'php5-curl', u'php5-dev', u'php5-gd', u'php5-gmp', u'php5-mcrypt', u'php5-memcache', u'php5-mysql', u'php5-xsl', u'php-apc', u'php-pear', u'python-mysqldb']) => {"changed": false, "item": ["apache2", "libapache2-mod-php5", "mysql-client", "mysql-server", "php5", "php5-cli", "php5-common", "php5-curl", "php5-dev", "php5-gd", "php5-gmp", "php5-mcrypt", "php5-memcache", "php5-mysql", "php5-xsl", "php-apc", "php-pear", "python-mysqldb"], "msg": "No package matching 'libapache2-mod-php5' is available"}
to retry, use: --limit @/tmp/php-ci/playbooks/bootstrap.retry

clean pear installations

All pear installations could be handled using {{ item }} and preferably without ignore_errors

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.