500 likes | 571 Views
This workshop was presented at PHP South Africa 2017 (https://phpsouthafrica.com) Composer is one of the most important and useful tools in a PHP developer’s arsenal, however, a majority of its most powerful features go untouched by most. Join me for a deep dive through this versatile toolbox hiding in the root of your project. Highlights of this workshop include: * Leveraging Semantic Versioning and Private Packages to abstract and maintain integration of your microservice APIs * Composer Repositories as a means of high deployment availability when South Africa is on the far end of the Internet topology * Composer’s scripts and plugins as an important element of your deployment and testing pipeline. Buckle up for a slew of examples and recipes with a PHP DevOps flavour. The ideas are not perfect but they are definitely interesting.
E N D
Advanced composer A Lot More Than Just ‘Install’ and ‘Update’ PHP South Africa 2017 Brad Mostert
Warning Buckle up for a slew of examples and recipes with a PHP DevOpsflavour. The ideas are not perfect but they are definitely interesting. /bsinkwa /mostertb
Who am I Senior developer at Afrihost PHP Joburg Organizer Server Shepard Smart Giving the Design Patterns in PHP presentation on Friday Crazy
Entrance test Have you done your pre-reading?
Entrance test Install or Update: Newly downloaded software package (e.g. checking out some framework to start a new project) Answer: Install
Entrance test Install or Update: Deploying code to server (committed lockfile) Answer: Install
Entrance test Install or Update: Deploying code to server (no lockfilecommited) Answer: Install
Entrance test Install or Update: Upgrade to the latest version of all your packages Answer: Update
Entrance test Install or Update: You’ve manually edited your composer.json Answer: Update
Environments Any Windows Users? Any Docker Users? Which Linux Distros?
Composer Environment: Memory Limit Problem: Solution: composer_wrapper.sh php -d memory_limit=2G /path/to/global/composer.phar $@ .bashrc alias composer=‘/path/to/composer_wrapper.sh’ • Better Than: • Updating memory_limit in php.ini
Composer Environment: Execution Time Problem: composer_wrapper.sh Solution: COMPOSER_PROCESS_TIMEOUT=600 php-d memory_limit=2G /path/to/global/composer.phar $@ Only affects the timeout of commands spawned by composer (e.g. git checkout) For individual projects: process-timeout node of composer.json
Composer Environment: XDEBUG Problem: Solution: prompt $ composer self-update Fixed in version 1.3.0 (2016-12-24). Update your stuff you filthy developer Composer essentially makes a copy of you php.ini in /tmp with the line to load xdbug commented out, then restarts itself using the new config
Composer Environment: oAuth Token Problem: OR Solution: prompt $ composer config -g github-oauth.github.com <oauthtoken> Create oAuth Token at: https://github.com/settings/tokens • Works for BitBucket and GitLab too • Also allows Auth for private repos • Good practice for CI, Build and Prod Servers Stored in ~/.composer/config.json
Composer Environment: oAuth Token – Travis CI .travis.yml • Token not committed to code base • All builds will use the latest token on account • Not available to Pull Requests • Alternate: travis encrypt gem
Production install flags • --prefer-dist • Super Github speed • Git export-ignore • --no-dev • Small deployment • Smaller attack surface • --optimize-autoloader • Power!
Docker: GOAL Composer Install (and post-install scripts) take time to run. This is compounded when deploying to many servers in a HA environment Bake composer install into a production image so that deployment becomes: docker pull docker stop docker start Docker Rollout (circa 2017 colourized)
Docker: Method One - Gameplan • Checkout just the composer.* files to docker build directory • Run docker build • Copy just composer.* files into build image • Run composer install (with --no-scripts) • Run composer clear-cache in same layer • Checkout project • composer dump-autoload • composer run-script
Docker: Method One - Example build.sh … # Checkout composer.* files from Git repo at specific tag gitarchive --format=tar –remote=ssh://git@reposerver/repo.gittags/${1} -- composer.* | tar -xf– # Run docker build passing the git tag as an argument docker build -t ${DOCKER_IMAGE_NAME}:$1 . --build-argrolloutTag=${1} # Some error checking and ‘docker push’ go here … The first argument to the build script is the name of the tag in the Git repo that we are deploying. The new docker image will be tagged with this same tag
Docker: Method One - Example Dockerfile … COPY composer.* ./ # Add your own prod flags for composer install RUN composer install --no-scripts && composer clear-cache ARG rolloutTag RUN git clone ssh://git@reposerver/repo.git/home/user/project/ && \gitfetch --all && \gitcheckout ${rolloutTag} RUN composer dump-autoload --optimize --no-dev RUN composer run-script post-install-cmd --no-dev# Optional …
Docker: Method One - Review • Composer install only run if composer.* files change • No composer cache in image – smaller image • But no composer cache used during install – slow install
Docker: Method Two Rube Goldberg Heath Robinson
Docker: Method TWO - Gameplan • Run docker build to checkout codebase but don’t run composer install • Instantiate container from new image • Mount the build server’s composer cache as volume • Run composer install normally • Commit container as final image
Docker: Method TWO - Example build.sh … docker build –t ${DOCKER_IMAGE_NAME}:${1}-checkout . --build-argrolloutTag=${1} docker run --name ${DOCKER_IMAGE_NAME}:${1}-composer--user prod_user \ -v ${PWD}/composer_cache:/home/prod_user/.composer \ ${DOCKER_IMAGE_NAME}:${1}-checkout composer install # Prod composer params docker commit \ --change="WORKDIR /home/user/project" \ --change='CMD ["apache2-foreground"]' \ --change="USER root” ${DOCKER_IMAGE_NAME}:${1}-composer \${DOCKER_IMAGE_NAME}:$1 # Cleanup ‘checkout’ image and ‘composer’ container # Push committed image
Docker: Method TWO - Review • Composer install run with every build • Error handling in build script a little more complex (due to more steps) • Composer install fast due to using build server’s cache (saves bandwidth too) • Place for other run-time config
Composer repositories ‘repositories’ node of composer.json allows you to specify package sources other than Packagist Note: Order is important. Composer will use the version of a package found in the first repository • Types: • VCS – git, svn, fossil or hg • – Github and BitBucket via API • PATH – directory on local machine • PEAR – yup • COMPOSER – Serve your own packages.json (like packagist) • PACKAGE – Treat some other project like a composer package
Composer repositories: Path Allows you to install a package from another directory on the same machine Great for dev. Understands local VCS
Composer repositories: Path Use with: & • Symlinks the path in to vendor directory: • Changes (including branch change) immediately available without composer update • Does behave as expected with ‘dev-branch’ version constrains . Rather use VCS repository if you need this • May occasionally require the autoloader to be re-dumped
Composer repositories: Path Prevents: .gitconfig [alias] yolo = !"git commit -m \"$(echo $(curl -s http://whatthecommit.com/index.txt)) (whatthecommit.com)\"" Followed by a rebase…
Composer repositories: Path Copy instead of Symlink: • Useful if you want to lock a a local package for a project • Branch version constraint needs to match what is currently checked out at install/update time • Getting updates to the package can be a pain (I generally delete the directory under vendor)
local composer.json COMPOSER ENV Variable prompt $ COMPOSER=composer-local.json composer install • Large changes to composer.json for local environment? • Specify some other JSON file • Will generate .lock with the same name
Composer repositories: VCS Intended for bug fixes to public packages As long as you keep the name node of the composer.json the same, the ‘order rule’ will mean that the version defined in your custom repository is used before the version from Packagist Type inferred from URL ( ‘ssh://’ , ‘.git’, etc.)
Composer repositories: VCS Also supports private repos Leverages the auth credentials of the user (e.g. ssh keys, ~/.composer/config) Very Powerful URL can be a filesystem path if you prefer to dev with a gitflow/rebase approach rather than a ‘PATH’ repository
Composer repositories: VCS Tagging a new version prompt $ git tag –a v1.2.3 –m “v1.2.3” $ git push $ git push --tags Sematic Versioning http://semver.org/
Composer repositories: VCS Update a single package prompt # In the repos that use the package $ composer update afrihost/cloud-broker-client # Check composer.lock now has you new version $ gitdiff composer.lock # Commit composer.lock $ gitadd omposer.lock $ gitcommit -m 'Brad is awesum’ $ gitpush
Composer repositories: VCS Maintaining Integration Between HTTP Microservices • Write HTTP Client Code as Private Package • Abstract API Behind PHP Functions/Classes • Functions return object (which has code completion) • Hide internal details like Transactional Consistency • Hide transport layer (e.g. Guzzle or Curl exceptions) • View your ‘interface’ for Semantic Versioning (breaking changes) in terms of PHP functions rather than API changes
Composer repositories: VCS Private HTTP Client Versioning • Write HTTP Client Code as Private Package • Breaking changes to PHP Interface • Major version • Telling microservice maintainers that everything else can just be updated • Endpoint Additions • Point Release • Telling microservice maintainers “Hey there is a cool new thing” • Breaking HTTP API Changes • Minor Version • Works if Regular updates to all projects • Manage breaks over several versions
Composer repositories: VCS Other Private HTTP Client Advantages • Ship non-sensitive config data in package • Default timeouts • CA Cert • Fits in well with Dependency Injection of frameworks • Good code reuse for integration code • Easier for developers to jump between codebases • Also works well for other cross-cutting concerns • Logging, Auth, Task Queuing, Templating
Composer repositories: VCS Caveat Composer cant load repositories recursively – only repositories in the root package are inspected Problem if we want our private packages to make use of other private packages Solution: Repository Type COMPOSER
Composer repositories: COMPOSER What Packagist provides packages.json Serve packages.json file which has details of available packages as well as its own schema elements (notify-batch, provider-includes and providers-url) @composer.json
Composer repositories: COMPOSER You probably don’t want to hand-curate this • Toran Proxy (toranproxy.com) • Project of Jordi’s being replaced by Private Packagist • Private Packagist(packagist.com) • SaaS and Self Hosted options • Web Interface • Some revenue supports Composer and Packagisy.org development • Access Control • Web Hooks • Statis(github.com/composer/satis) • Free • CLI Based • Requires you to set up method of serving content and auth
Composer repositories: STATIS statis.json Define all your private repositories as well as the range of package versions that you are interested in Run statis to generate a packages .json Still need to serve it yourself (https/ssh)
Composer repositories: STATIS Update your projects to use COMPOSER repo composer.json
Composer repositories: STATIS Mirror Content Improve speed Improve reliability (In South Africa, there is typically a lot of network between you and Github) Protection against original Git Repo disappearing ‘Offline Deployments’ (financial, remote)
Composer repositories: STATIS Auth getcomposer.org/doc/articles/handling-private-packages-with-satis.md#security • SSH • Public/Private Key • HTTPS • Client Cert • HTTP Header • Authorized Bearer, API Token… • Basic Auth prompt Stored per project or globally (-g) in ~/.composer/auth.json
GIT ARCHIVE Exclude stuff from Dist versions .gitattributes /Tests export-ignore /.gitattributes export-ignore /.travis.yml export-ignore /phpunit.xml export-ignore Github uses ‘git archive’ to generate the release artefacts
Prefer-lowest Prefer-Lowest in CI/Test Chain .travis.yml
Scripts Run PHP Callback, PHP Script or CLI Commands at Event during composer lifecycle
Scripts: ideas COMPOSER_DEV_MODE env variable during install and update with value for --no-dev • Framework steps • cache clear, asset setup • SensioDistributionBundle • Build chains outside of PHP (npm,gulp) • Deployment notification • Continuous Deployment, Slack Notification • Track Private Package version usage on Production Hosts (extension to ‘notify-batch’) • Run test suite after install or update
Questions? PHP South Africa 2017 Brad Mostert /bsinkwa /mostertb