├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── ansistrano ├── ansible.cfg ├── applications │ ├── default.yml │ ├── symfony2.yml │ ├── symfony3.yml │ └── typo3.yml ├── deploy ├── deploy-status.yml ├── deploy.yml ├── files │ └── opcode-clear.php ├── inventory │ ├── group_vars │ │ └── .gitkeep │ ├── host_vars │ │ └── .gitkeep │ └── vagrant ├── projects │ └── default.yml ├── roles │ ├── deployment-status-failure │ │ └── tasks │ │ │ └── main.yml │ ├── deployment-status-startup │ │ └── tasks │ │ │ └── main.yml │ └── deployment-status-success │ │ └── tasks │ │ └── main.yml ├── rsync-excludes └── tasks │ ├── build.yml │ ├── build │ ├── .gitkeep │ ├── commands.yml │ └── makefile.yml │ ├── finalize.yml │ ├── finalize │ ├── .gitkeep │ ├── commands.yml │ └── php-opcode-cache.yml │ ├── migration.yml │ ├── migration │ ├── .gitkeep │ ├── commands.yml │ └── permissions.yml │ ├── teardown.yml │ └── teardown │ ├── .gitkeep │ └── validate.yml ├── backup └── .gitkeep ├── docker-compose.yml ├── etc ├── crontab ├── database.yml ├── environment.yml ├── known_hosts │ ├── bitbucket.com │ ├── github.com │ └── gitlab.com ├── provision.yml └── samson.conf ├── mysql ├── Dockerfile └── conf │ └── mysql-docker.cnf ├── provision └── roles │ └── samson-deployment │ ├── defaults │ └── main.yml │ └── tasks │ ├── build.yml │ ├── build │ ├── cron.yml │ ├── permissions.yml │ ├── ssh.yml │ └── storage.yml │ └── main.yml └── ssh ├── .gitkeep ├── config └── known_hosts /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | 8 | [*] 9 | end_of_line = lf 10 | insert_final_newline = true 11 | indent_style = space 12 | indent_size = 4 13 | 14 | [Makefile] 15 | indent_style = tab 16 | 17 | [*.yml] 18 | indent_size = 2 19 | 20 | [*.conf] 21 | indent_size = 2 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /ssh/id_rsa 3 | /ssh/id_rsa.pub 4 | /backup/* 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [WebDevOps.io Samson Deployment](https://github.com/webdevops/samson-deployment). 4 | 5 | ## [1.4.0] - 2016-04-06 6 | ### Changed 7 | - Fixed ssh control path length for very long host names (see https://github.com/ansible/ansible/issues/11536) 8 | - Set default ansistrano deployment strategy to "rsync" instead of "symlink" to fix issues (see https://github.com/zendtech/ZendOptimizerPlus/issues/126) 9 | 10 | ## [1.3.0] - 2016-03-28 11 | ### Changed 12 | - Moved /app/db to /storage/db (make backup before update!) 13 | - Added storage for npm and composer 14 | - Implemented reading of samson project/group environment variables when using ansistrano 15 | - Local tasks only run once for all affected hosts 16 | 17 | ## [1.2.0] - 2016-02-24 18 | ### Changed 19 | - TYPO3 deployment support 20 | - rsync excludes because of deployment issues 21 | 22 | ### Removed 23 | - MySQL support, switched to sqlite because of stability issues 24 | 25 | ## [1.1.0] - 2016-02-16 26 | ### Added 27 | - Added basic symfony 2 und 3 support 28 | - Added support for prefetched ssh public keys (more secure) 29 | - Added Makefile for common tasks 30 | - Added `DEPLOYMENT_PROJECT` support 31 | 32 | ### Changed 33 | - Improved deployment README 34 | - Renamed /opt/deployment to /opt/ansistrano 35 | - Cleaned up etc/environment.yml 36 | - Switched to Apache 2.0 license to match zendesk/samson license 37 | 38 | ## [1.0.1] - 2016-02-16 39 | ### Changed 40 | - Updated README 41 | 42 | ## [1.0.0] - 2016-02-16 43 | Initial revision 44 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM webdevops/samson-deployment 2 | 3 | ENV RAILS_ENV="production" 4 | ENV PYTHONUNBUFFERED=1 5 | 6 | # Setup 7 | COPY etc/crontab /etc/cron.d/samson-deployment 8 | COPY etc/database.yml /app/config/database.yml 9 | COPY etc/samson.conf /app/.env 10 | COPY etc/provision.yml /app/provision.yml 11 | COPY etc/known_hosts/ /root/.known_ssh_prefetched 12 | 13 | # Deploy ansistrano scripts 14 | COPY ansistrano/ /opt/ansistrano/ 15 | 16 | # Deploy ssh configuration/keys 17 | COPY ssh/ /home/application/.ssh/ 18 | 19 | COPY provision/ /opt/docker/provision/ 20 | 21 | RUN bash /opt/docker/bin/control.sh provision.role.build samson-deployment \ 22 | && /opt/docker/bin/control.sh service.enable cron \ 23 | && bash /opt/docker/bin/bootstrap.sh 24 | 25 | VOLUME ["/tmp", "/storage"] 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 WebDevOps.io 2 | Copyright 2014 Zendesk 3 | 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ARGS = $(filter-out $@,$(MAKECMDGOALS)) 2 | MAKEFLAGS += --silent 3 | .PHONY: backup restore 4 | 5 | list: 6 | sh -c "echo; $(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print A[i]}' | grep -v '__\$$' | grep -v 'Makefile'| sort" 7 | 8 | restart: rebuild 9 | 10 | start: 11 | docker-compose up -d 12 | 13 | stop: 14 | docker-compose stop 15 | 16 | log: 17 | docker-compose logs 18 | 19 | rebuild: 20 | docker-compose build 21 | docker-compose up -d --force-recreate 22 | 23 | update: 24 | docker pull webdevops/samson-deployment 25 | docker-compose build 26 | docker-compose up -d --force-recreate 27 | 28 | backup: 29 | rm -rf ./backup/db/ 30 | docker exec -it -u root $$(docker-compose ps -q app) service samson stop 31 | docker cp $$(docker-compose ps -q app):/storage/db/ ./backup/db/ 32 | docker exec -it -u root $$(docker-compose ps -q app) service samson start 33 | 34 | restore: 35 | docker exec -it -u root $$(docker-compose ps -q app) service samson stop 36 | docker exec -it -u root $$(docker-compose ps -q app) rm -rf /storage/db/ 37 | docker cp ./backup/db/ $$(docker-compose ps -q app):/storage/db/ 38 | docker exec -it -u root $$(docker-compose ps -q app) chown -R application:application /storage/db/ 39 | docker exec -it -u root $$(docker-compose ps -q app) service samson start 40 | 41 | shell: 42 | docker exec -it -u application $$(docker-compose ps -q app) /bin/bash 43 | 44 | root: 45 | docker exec -it -u root $$(docker-compose ps -q app) /bin/bash 46 | 47 | ssh-key: 48 | if [ ! -f "./ssh/id_rsa" ]; then \ 49 | echo "Generating ssh key, will take some time ..."; \ 50 | ssh-keygen -b 6144 -N "" -C "Samson deployment service" -f "./ssh/id_rsa"; \ 51 | else \ 52 | echo ""; \ 53 | echo "[ERROR] SSH key already exists!"; \ 54 | echo ""; \ 55 | exit 1; \ 56 | fi 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Samson deployment](https://static.webdevops.io/samson-deployment.svg) 2 | 3 | [ZenDesk's](https://www.zendesk.com/) Deployment web ui with Ansible Ansistrano, Capistrano and PHP Deployer support 4 | 5 | Installed packages: 6 | * [Samson deployment web ui](https://github.com/zendesk/samson) 7 | * [Ansible](https://www.ansible.com/) with [Ansistrano](https://github.com/ansistrano) 8 | * [Capistrano](http://capistranorb.com/) 9 | * [PHP Deployer](http://deployer.org/) 10 | * git 11 | * rsync 12 | * docker & docker-compose (as client) 13 | * npm, gulp, grunt, bower 14 | * java (jre 7) 15 | * PHP cli & [composer](https://getcomposer.org/) 16 | 17 | ### What? 18 | (from [ZenDesk/Samson repository](https://github.com/zendesk/samson)) 19 | 20 | A web interface for deployments. 21 | 22 | **View the current status of all your projects:** 23 | 24 | ![](http://f.cl.ly/items/3n0f0m3j2Q242Y1k311O/Samson.png) 25 | 26 | **Allow anyone to watch deploys as they happen:** 27 | 28 | ![](http://cl.ly/image/1m0Q1k2r1M32/Master_deploy__succeeded_.png) 29 | 30 | **View all recent deploys across all projects:** 31 | 32 | ![](http://cl.ly/image/270l1e3s2e1p/Samson.png) 33 | 34 | ## Setup 35 | 36 | * [Generate GitHub appliation key](https://github.com/settings/developers) 37 | * [Generate GitHub access token](https://github.com/settings/tokens) 38 | * Edit `conf/samson.conf`: 39 | * Set GitHub appliation credentials (`GITHUB_CLIENT_ID`, `GITHUB_SECRET`) 40 | * Set GitHub access token (`GITHUB_TOKEN`) 41 | * Set `SECRET_TOKEN` (random string with length of 128, can be generated with `openssl rand -hex 128| head -c 128`) 42 | * Set `DEFAULT_URL` (must be accessable url for SSO callbacks) 43 | * Edit `etc/provision.yml` to setup public key fetching of `.ssh/known_hosts` 44 | * Fixed known_host keys can be stored inside `etc/known_hosts` folder and can be generated with `ssh-keyscan -H HOSTNAME > etc/known_hosts/HOSTNAME` (very secure) 45 | * All hosts without stored known_host keys will be automatically fetched when Dockerfile build is running (less secure) 46 | * Add ssh keys to `ssh` (will be deployed to `/home/application/.ssh`) or generate an new one with `make ssh-key` 47 | * Run `docker-compose up -d` or `make restart` 48 | 49 | ## Ansistrano deployment 50 | 51 | For an easy project independed deployment you can use the predefined deployment runner (based on Ansistrano). 52 | 53 | Use following as deployment command: 54 | 55 | ``` 56 | export DEPLOYMENT_INVENTORY=vagrant 57 | export DEPLOYMENT_DEPLOY_TO=/var/www/target-deployment-path 58 | /opt/ansistrano/deploy 59 | ``` 60 | 61 | ### Deploy variables 62 | 63 | Variable | Description 64 | ------------------------------ | ------------------------------------------------------ 65 | DEPLOYMENT_INVENTORY | Inventory file for deployment **(required)** 66 | DEPLOYMENT_DEPLOY_TO | Target deployment directory **(required)** 67 | DEPLOYMENT_CURRENT_DIR | Link name of the htdocs path (default: current) 68 | DEPLOYMENT_APPLICATION | Include variables for specific application (eg. for shared paths, eg `typo3` for including `deployment/applications/typo3.yml`) 69 | DEPLOYMENT_PROJECT | Include variables for specific project (eg. for shared paths, eg `foobar` for including `deployment/projects/foobar.yml`) 70 | DEPLOYMENT_OPTS | Ansible options (can also be append to `/opt/ansistrano/deploy`) 71 | DEPLOYMENT_PLAYBOOK | Ansible playbook (default is `deploy`) 72 | DEPLOYMENT_URL | URL to website (required for eg. PHP opcode cache clearing) 73 | 74 | ### Customization 75 | 76 | Variable | Description 77 | --------------------------- | ------------------------------------------------------ 78 | Ansible inventory | [deployment/inventory](ansistrano/inventory) 79 | Common project build task | [deployment/tasks/build.yml](ansistrano/tasks/build.yml) 80 | Main deploy playbook | [deployment/deploy.yml](ansistrano/deploy.yml) 81 | Common rsync excludes | [deployment/rsync-excludes](ansistrano/rsync-excludes) 82 | 83 | ## PHP deployer 84 | Use following as deployment command: 85 | 86 | ``` 87 | dep deploy 88 | ``` 89 | 90 | ## Makefile 91 | 92 | Command | Description 93 | --------------------------- | ------------------------------------------------------ 94 | `make restart` | Restart Samson (and update/deploy configuration) 95 | `make start` | Start Samson 96 | `make stop` | Stop Samson 97 | `make log` | Show logs 98 | `make update` | Update Samson docker image (`docker pull`) and restart Samson 99 | `make ssh-key` | Generate new ssh-key (will not overwrite if exists) 100 |
| 101 | `make backup` | Run backup (app:/app/db/ will be copied to ./backup/db/) 102 | `make restore` | Run restore (./backup/db/ will be copied to app:/app/db/) 103 |
| 104 | `make shell` | Jump into shell inside the container (as `application` user) 105 | `make root` | Jump into shell inside the container (as `root` user) 106 | 107 | ## Project specific deployment 108 | 109 | If you need a project specific deployment feel free to put your ansistrano deployment within your project sources. 110 | Your deployment task should look like: 111 | 112 | ansible-playbook -i inventory/server deploy.yml 113 | 114 | ## SSH - jump to servers behind gateways transparently 115 | 116 | With ssh you can jump over multiple servers transparently to reach servers behinde ssh gateways, use the `ssh/config` 117 | file for configuration: 118 | 119 | ``` 120 | Host ssh-gateway 121 | Hostname ssh-gateway.example.com 122 | User foo 123 | 124 | Host server-behind-gateway 125 | Hostname server-behind-ssh-gateway.example.com 126 | User root 127 | ProxyCommand ssh ssh-gateway -W %h:%p 128 | ``` 129 | 130 | Now you can use `server-behind-gateway` as target host for SSH'ing at it will automatically jump over `ssh-gateway` to 131 | reach this server. 132 | -------------------------------------------------------------------------------- /ansistrano/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | ask_sudo_pass = false 3 | ask_pass = false 4 | 5 | # dont show command "better use xxx module" warning 6 | command_warnings = False 7 | 8 | # uncomment this to disable SSH key host checking 9 | #host_key_checking = False 10 | 11 | force_color = 1 12 | nocolor = 0 13 | nocows = 1 14 | 15 | [ssh_connection] 16 | control_path = %(directory)s/%%C 17 | -------------------------------------------------------------------------------- /ansistrano/applications/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ############################# 4 | # Ansistrano 5 | ############################# 6 | 7 | # Rsync files from this directory (with trailing /) 8 | ansistrano_deploy_from: "{{ lookup('env','DEPLOYMENT_DEPLOY_FROM') }}" 9 | 10 | # Rsync files to this directory (with releases, shared and current folder) 11 | ansistrano_deploy_to: "{{ lookup('env','DEPLOYMENT_DEPLOY_TO') }}" 12 | 13 | # Folder name for the releases 14 | ansistrano_version_dir: "releases" 15 | 16 | # Softlink name for the current release (default "current") 17 | ansistrano_current_dir: "{{ lookup('env','DEPLOYMENT_CURRENT_DIR') }}" 18 | 19 | # Deploy strategy for "current" directory (options: rsync, symlink) 20 | # For symlink for PHP see https://github.com/zendtech/ZendOptimizerPlus/issues/126 21 | # but applied to other languages as well 22 | # -> for apache use mod_realdoc 23 | # -> for nginx use realpath setting 24 | ansistrano_current_via: "rsync" 25 | 26 | # Shared paths to symlink to release dir 27 | ansistrano_shared_paths: [] 28 | 29 | # Number of releases to keep in your hosts, if 0, unlimited releases will be kept 30 | ansistrano_keep_releases: 3 31 | 32 | # Rsync extra paraemters (will be append to rsync command) 33 | ansistrano_rsync_extra_params: "--exclude-from={{ playbook_dir }}/rsync-excludes --no-o --no-g" 34 | 35 | # Hooks 36 | ansistrano_before_setup_tasks_file: "{{ playbook_dir }}/tasks/build.yml" 37 | ansistrano_before_symlink_tasks_file: "{{ playbook_dir }}/tasks/migration.yml" 38 | ansistrano_after_symlink_tasks_file: "{{ playbook_dir }}/tasks/finalize.yml" 39 | ansistrano_after_cleanup_tasks_file: "{{ playbook_dir }}/tasks/teardown.yml" 40 | 41 | ############################# 42 | # Deployment (Hooks) 43 | ############################# 44 | 45 | # Set the deployment base directory (for running local tasks) 46 | deployment_base: "{{ lookup('env','DEPLOYMENT_DEPLOY_FROM') }}" 47 | 48 | # Run defined Makefile task (on deployment server, before rsync) 49 | deployment_makefile_task: "build" 50 | 51 | # Tasks for building up application (on deployment server, before rsync) 52 | deployment_build_tasks: [] 53 | 54 | # Tasks for migration (before going live on remote server) 55 | deployment_migration_tasks: [] 56 | 57 | # Tasks for finalize (after going live on remote server) 58 | deployment_finalize_tasks: [] 59 | 60 | # Application name (for conditions) 61 | deployment_application: "default" 62 | 63 | # Deployment permissions (on remote server) 64 | deployment_permission_owner: "" 65 | deployment_permission_group: "" 66 | deployment_permission_mode: "u=rwX,g=rX,o=rX" 67 | 68 | # Deployment special file or directory permissions (on remote server) 69 | deployment_permissions: [] 70 | 71 | # URL to instance (eg. for PHP OpCode cache clearing) 72 | deployment_web_url: "{{ lookup('env','DEPLOYMENT_URL') }}" 73 | 74 | # Path Prefix for document root 75 | deployment_web_path_prefix: "" 76 | 77 | # Enable PHP opcode cache clearing (requires deployment_web_url) 78 | deployment_php_opcode_cache_clear: False 79 | 80 | # Options for curl 81 | deployment_curl_opts: "" 82 | 83 | # Enable for final website validation check via curl request (requires deployment_web_url) 84 | deployment_validate_website: False 85 | -------------------------------------------------------------------------------- /ansistrano/applications/symfony2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Application name (for conditions) 4 | deployment_application: "symfony3" 5 | 6 | # Shared paths to symlink to release dir 7 | ansistrano_shared_paths: 8 | - app/logs -------------------------------------------------------------------------------- /ansistrano/applications/symfony3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Application name (for conditions) 4 | deployment_application: "symfony3" 5 | 6 | # Shared paths to symlink to release dir 7 | ansistrano_shared_paths: 8 | - var/logs -------------------------------------------------------------------------------- /ansistrano/applications/typo3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Application name (for conditions) 4 | deployment_application: "typo3" 5 | 6 | # Shared paths to symlink to release dir 7 | ansistrano_shared_paths: 8 | - web/fileadmin 9 | - web/uploads 10 | - web/typo3conf/l10n 11 | 12 | # Deployment special file or directory permissions (on remote server) 13 | deployment_permissions: 14 | - { path: "web/typo3conf/PackageStates.php", mode: "0664" } 15 | - { path: "web/typo3conf/LocalConfiguration.php", mode: "0660" } 16 | 17 | # Path Prefix for document root 18 | deployment_web_path_prefix: "/web" 19 | 20 | # Enable PHP opcode cache clearing (requires deployment_web_url) 21 | deployment_php_opcode_cache_clear: True 22 | -------------------------------------------------------------------------------- /ansistrano/deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR="$(dirname $(readlink -f "$0"))" 4 | 5 | DEBUG=0 6 | 7 | export PYTHONUNBUFFERED=1 8 | export ANSIBLE_CONFIG="${SCRIPT_DIR}/ansible.cfg" 9 | 10 | ## Read vars from .env 11 | if [[ -f "$(pwd)/.env" ]]; then 12 | set -o allexport 13 | . "$(pwd)/.env" 14 | set +o allexport 15 | fi 16 | 17 | if [ -z "$DEPLOYMENT_INVENTORY" ]; then 18 | echo "[ERROR] DEPLOYMENT_INVENTORY not set" 19 | exit 1 20 | fi 21 | 22 | if [ -z "$DEPLOYMENT_DEPLOY_TO" ]; then 23 | echo "[ERROR] DEPLOYMENT_DEPLOY_TO not set" 24 | exit 1 25 | fi 26 | 27 | if [ -z "$DEPLOYMENT_DEPLOY_FROM" ]; then 28 | export DEPLOYMENT_DEPLOY_FROM="$(pwd)/" 29 | fi 30 | 31 | if [ -z "$DEPLOYMENT_CURRENT_DIR" ]; then 32 | export DEPLOYMENT_CURRENT_DIR="current" 33 | fi 34 | 35 | if [ -z "$DEPLOYMENT_APPLICATION" ]; then 36 | export DEPLOYMENT_APPLICATION="default" 37 | fi 38 | 39 | if [ -z "$DEPLOYMENT_PROJECT" ]; then 40 | export DEPLOYMENT_PROJECT="default" 41 | fi 42 | 43 | 44 | if [ -z "$DEPLOYMENT_OPTS" ]; then 45 | DEPLOYMENT_OPTS="" 46 | fi 47 | 48 | if [ -z "$DEPLOYMENT_PLAYBOOK" ]; then 49 | DEPLOYMENT_PLAYBOOK="deploy" 50 | fi 51 | 52 | function displayEnvVars() { 53 | env | grep DEPLOYMENT_ | sed -e 's/^/» /' 54 | } 55 | 56 | function ansibleDeployStatus() { 57 | if [[ "$DEBUG" -eq 0 ]]; then 58 | ansible-playbook -i localhost, -c local "${SCRIPT_DIR}/deploy-status.yml" &> /dev/null 59 | else 60 | ansible-playbook -i localhost, -c local "${SCRIPT_DIR}/deploy-status.yml" 61 | fi 62 | } 63 | 64 | function calcDuration() { 65 | export DEPLOYMENT_DURATION_TIME="$SECONDS" 66 | export DEPLOYMENT_DURATION_MINUTES="$(($DEPLOYMENT_DURATION_TIME / 60))" 67 | export DEPLOYMENT_DURATION_SECONDS="$(($DEPLOYMENT_DURATION_TIME % 60))" 68 | export DEPLOYMENT_DURATION="${DEPLOYMENT_DURATION_MINUTES}:$(printf "%02d" $DEPLOYMENT_DURATION_SECONDS) min" 69 | } 70 | 71 | function runDeployment() { 72 | ansible-playbook -i "${SCRIPT_DIR}/inventory/${DEPLOYMENT_INVENTORY}" "${SCRIPT_DIR}/${DEPLOYMENT_PLAYBOOK}.yml" $DEPLOYMENT_OPTS "$@" 73 | export DEPLOYMENT_RC="$?" 74 | } 75 | 76 | echo "" 77 | echo "" 78 | echo "# Environment variables" 79 | displayEnvVars 80 | 81 | ## run status report (startup) 82 | ansibleDeployStatus 83 | 84 | echo "" 85 | echo "" 86 | echo "# Executing Ansistrano" 87 | 88 | ## reset timer 89 | SECONDS=0 90 | 91 | ## run deployment 92 | runDeployment "$@" 93 | 94 | ## calculate duration 95 | calcDuration 96 | 97 | ## run status report (finish) 98 | ansibleDeployStatus 99 | 100 | echo "" 101 | echo "" 102 | echo "» Duration: ${DEPLOYMENT_DURATION}" 103 | echo "" 104 | 105 | exit "$DEPLOYMENT_RC" 106 | 107 | -------------------------------------------------------------------------------- /ansistrano/deploy-status.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Deployment reporting tasks 3 | hosts: all 4 | gather_facts: false 5 | vars: 6 | DEPLOYMENT_RC: "{{ lookup('env','DEPLOYMENT_RC') }}" 7 | DEPLOYMENT_DURATION: "{{ lookup('env','DEPLOYMENT_DURATION') }}" 8 | roles: 9 | - { role: deployment-status-startup, when: DEPLOYMENT_RC == "" } 10 | - { role: deployment-status-failure, when: DEPLOYMENT_RC != "0" and DEPLOYMENT_RC != "" } 11 | - { role: deployment-status-success, when: DEPLOYMENT_RC == "0" } 12 | -------------------------------------------------------------------------------- /ansistrano/deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Deployment 3 | hosts: all 4 | vars_files: 5 | - applications/default.yml 6 | - applications/{{ lookup('env','DEPLOYMENT_APPLICATION') }}.yml 7 | - projects/{{ lookup('env','DEPLOYMENT_PROJECT') }}.yml 8 | roles: 9 | - { role: carlosbuenosvinos.ansistrano-deploy } 10 | -------------------------------------------------------------------------------- /ansistrano/files/opcode-clear.php: -------------------------------------------------------------------------------- 1 | /dev/null 5 | 4 5 * * * root dep self-update &> /dev/null -------------------------------------------------------------------------------- /etc/database.yml: -------------------------------------------------------------------------------- 1 | <% 2 | uri = URI(ENV['MYSQL_URL'] || 'mysql://root:sql@mysql:3306/samson') 3 | uri.scheme = 'mysql2' 4 | %> 5 | 6 | production: 7 | adapter: sqlite3 8 | database: /storage/db/database.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | staging: 13 | adapter: sqlite3 14 | database: /storage/db/database.sqlite3 15 | pool: 5 16 | timeout: 5000 17 | 18 | development: 19 | adapter: sqlite3 20 | database: /storage/db/database.sqlite3 21 | pool: 5 22 | timeout: 5000 23 | 24 | test: 25 | adapter: sqlite3 26 | database: /storage/db/database.sqlite3 27 | pool: 5 28 | timeout: 5000 29 | 30 | -------------------------------------------------------------------------------- /etc/environment.yml: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Environment Configuration 3 | # - feel free to edit - 4 | # -> for most changes you only have to 5 | # docker-compose up -d 6 | # to apply them 7 | ####################################### 8 | 9 | ####################################### 10 | # Samson settings 11 | MYSQL_URL=mysql://root:sql@mysql:3306/samson 12 | 13 | ####################################### 14 | # MySQL settings 15 | # -> if you change these settings 16 | # you have to remove the database: 17 | # docker-compose rm mysql 18 | # because it's stored database in 19 | # volume and provisioning is only 20 | # done once. 21 | MYSQL_ROOT_PASSWORD=sql 22 | MYSQL_USER=samson 23 | MYSQL_PASSWORD=samson 24 | MYSQL_DATABASE=samson 25 | 26 | 27 | -------------------------------------------------------------------------------- /etc/known_hosts/bitbucket.com: -------------------------------------------------------------------------------- 1 | # bitbucket.com:22 SSH-2.0-OpenSSH_6.4 2 | |1|36DT5/mpuswvt+2oGlCrx8DZ9EQ=|NQ9nL95+12dbGJI8JtrFHL88ogU= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== 3 | # bitbucket.com:22 SSH-2.0-OpenSSH_5.3 4 | # bitbucket.com:22 SSH-2.0-OpenSSH_5.3 5 | -------------------------------------------------------------------------------- /etc/known_hosts/github.com: -------------------------------------------------------------------------------- 1 | |1|LXmaOLU+O3acZyv84Z8EZcnOc3U=|wMsFOgS9hOl6kLuHdQySlyfT8bo= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== 2 | -------------------------------------------------------------------------------- /etc/known_hosts/gitlab.com: -------------------------------------------------------------------------------- 1 | # gitlab.com:22 SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.6 2 | |1|PfJ6/iOiXGYeje5RBwehqA7x0ZA=|2g4x0QIByX+yI3rr/SVWOpSwlgw= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= 3 | # gitlab.com:22 SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.6 4 | |1|U7DzVjlR0jfPpXigqSaDY4HziEM=|WKMZ5x/b6nTCkFA/B9UI/z+ln88= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 5 | # gitlab.com:22 SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.6 6 | |1|4dxeUV6vHkOXBMYJXURBbEV1QNY=|YMBnqRrZZWyzfjlPIo4qVuAtwnM= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf 7 | -------------------------------------------------------------------------------- /etc/provision.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | SSH: 4 | # List of hostnames which should be automatically fetched for .ssh/known_hosts 5 | # hostname: hostname or ip of remote host 6 | # file: pre-fetched ssh-keyscan server public key 7 | # inside etc/known_hosts 8 | # (otherwise there will be on-provision key fetch) 9 | # port: ssh port of remote host 10 | # opts: ssh-keyscan additional parameters, see "man ssh-keyscan" 11 | # Examples: 12 | # - { hostname: "your-host.example" } 13 | # - { hostname: "your-host.example", port: "2222" } 14 | # - { hostname: "your-host.example", opts: "2222" } 15 | known_hosts: 16 | - { hostname: "github.com", file: "github.com" } 17 | - { hostname: "gitlab.com", file: "gitlab.com" } 18 | - { hostname: "bitbucket.com", file: "bitbucket.com" } 19 | -------------------------------------------------------------------------------- /etc/samson.conf: -------------------------------------------------------------------------------- 1 | PLUGINS=all,-slack 2 | DEFAULT_URL=http://samson.vm:9080/ 3 | SECRET_TOKEN={bundle exec rake secret} 4 | 5 | # GITHUB_CLIENT_ID={fill me in} 6 | # GITHUB_SECRET={fill me in} 7 | # GITHUB_TOKEN={fill me in} 8 | # GITHUB_ORGANIZATION={optional 9 | # GITHUB_ORGANIZATION={optional, eg. zendesk} 10 | # GITHUB_ADMIN_TEAM={optional, eg. owners} 11 | # GITHUB_DEPLOY_TEAM={optional, eg. developers} 12 | # GITHUB_WEB_URL={optional, eg. github.com} 13 | # GITHUB_API_URL={optional, eg. api.github.com} 14 | 15 | # GOOGLE_CLIENT_ID={optional, fill me in} 16 | # GOOGLE_CLIENT_SECRET={optional, fill me in} 17 | # GOOGLE_DOMAIN={optional, set to @company.com to limit login only for people at Company} 18 | 19 | #The following settings is required if auth with LDAP is enabled. 20 | # LDAP_TITLE={fill me in, eg. My LDAP Server} 21 | # LDAP_HOST=192.168.25.188 22 | # LDAP_PORT=389 23 | # LDAP_BASE='dc=domain,dc=com' 24 | # LDAP_UID=uid 25 | # LDAP_PASSWORD=myldapsecret 26 | 27 | # AUTH_GITHUB={optional, set to 0 to disable Github authentication} 28 | # AUTH_GOOGLE={optional, set to 0 to disable Google authentication} 29 | # AUTH_LDAP={optional, set to 0 to disable LDAP authentication} 30 | 31 | # BYPASS_EMAIL={optional, email destination that is alerted about buddy_check bypasses} 32 | # BYPASS_JIRA_EMAIL={optional, jira email destination that is alerted about buddy_check bypasses} 33 | # BYPASS_DETAILS={optional 'Some text explaining bypass procedure'} 34 | # BUDDY_CHECK_FEATURE={optional, set to 1 to enable buddy_check feature; 0 to disable} 35 | 36 | # BUDDY_CHECK_TIME_LIMIT={optional, set to 20 for max minutes a deploy is pending} 37 | 38 | # PROJECT_CREATED_NOTIFY_ADDRESS=bobby-the-security-auditor@yourcompany.com 39 | 40 | # DEPLOY_GROUP_FEATURE={optional, set to 1 to enable Environments and DeployGroups} 41 | 42 | # DOCKER_FEATURE={optional, set to 1 for experimental docker support} 43 | 44 | # SLACK_TOKEN={ required for the slack integration } 45 | 46 | # FLOWDOCK_API_TOKEN={ required for the flowdock integration } 47 | 48 | # FORCE_SSL={optional, set to 1 to require SSL} 49 | 50 | ## JIRA_BASE_URL, if set, would enable the auto-detection of JIRA issue keys 51 | ## (e.g., KEY-123, SAMSON-456) in the titles and bodies of the pull requests 52 | ## associated with a deploy. The auto-detected JIRA issues will be displayed 53 | ## and linked (by prepending JIRA_BASE_URL) in the "JIRA Issues" tab of a deploy 54 | ## 55 | ## Full absolute JIRA URLs will still be detected, and they will take precedence 56 | ## over generated ones (i.e., if JIRA_BASE_URL is https://a.atlassian.net/browse/ 57 | ## and both "KEY-123" and "http://z.atlassian.net/browse/KEY-123" appear in a 58 | ## pull request's title and body, only "http://z.atlassian.net/browse/KEY-123" 59 | ## would appear in the "JIRA Issues" tab). 60 | ## 61 | # JIRA_BASE_URL={optional, eg. https://jira.atlassian.net/browse/} -------------------------------------------------------------------------------- /mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | #++++++++++++++++++++++++++++++++++++++ 2 | # MySQL Docker container 3 | #++++++++++++++++++++++++++++++++++++++ 4 | # 5 | # Official images: 6 | # 7 | # mysql - official MySQL from Oracle 8 | # https://hub.docker.com/r/library/mysql/ 9 | # 10 | #++++++++++++++++++++++++++++++++++++++ 11 | 12 | FROM mysql:5.7 13 | 14 | ADD conf/mysql-docker.cnf /etc/mysql/conf.d/z99-docker.cnf 15 | -------------------------------------------------------------------------------- /mysql/conf/mysql-docker.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | 3 | ################################################# 4 | ## Charset 5 | 6 | character-set-server=utf8 7 | collation-server=utf8_general_ci 8 | 9 | ################################################# 10 | ## Buffers 11 | 12 | key_buffer_size = 200M 13 | query_cache_size = 100M 14 | 15 | innodb_buffer_pool_size = 250M 16 | innodb_log_buffer_size = 10M 17 | 18 | tmp_table_size = 200M 19 | max_heap_table_size = 200M 20 | 21 | open-files-limit = 2048 22 | thread_cache_size = 12 23 | 24 | # Fast SQL import 25 | local-infile=1 26 | 27 | ################################################# 28 | ## Misc 29 | 30 | ## direct access to files, avoid OS-caching (not posssible in docker) 31 | ; innodb_flush_method=O_DIRECT 32 | 33 | transaction-isolation=REPEATABLE-READ 34 | ;transaction-isolation=READ-COMMITTED 35 | 36 | ################################################# 37 | ## Query cache 38 | 39 | query_cache_limit = 256k 40 | query_cache_size = 60M 41 | query_cache_type = 1 42 | 43 | ################################################# 44 | ## Query log 45 | 46 | slow-query-log 47 | slow_query_log_file = /dev/stderr 48 | long_query_time = 1 49 | ; log-queries-not-using-indexes 50 | 51 | ################################################# 52 | ## Connections 53 | ## 54 | ## keep connections low because each conncetion 55 | ## will have their own buffers 56 | ## - prevent swapping here - 57 | 58 | max_connections = 20 59 | max_allowed_packet = 16M 60 | 61 | -------------------------------------------------------------------------------- /provision/roles/samson-deployment/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | APPLICATION_USER: "{{ lookup('env','APPLICATION_USER') }}" 4 | APPLICATION_GROUP: "{{ lookup('env','APPLICATION_GROUP') }}" 5 | -------------------------------------------------------------------------------- /provision/roles/samson-deployment/tasks/build.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include: build/ssh.yml 4 | - include: build/cron.yml 5 | - include: build/storage.yml 6 | - include: build/permissions.yml 7 | 8 | -------------------------------------------------------------------------------- /provision/roles/samson-deployment/tasks/build/cron.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Add newline to crontab 4 | raw: 'echo >> /etc/cron.d/samson-deployment' 5 | -------------------------------------------------------------------------------- /provision/roles/samson-deployment/tasks/build/permissions.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - file: 4 | path: "{{ item.path }}" 5 | owner: "{{ APPLICATION_USER }}" 6 | group: "{{ APPLICATION_GROUP }}" 7 | state: "{{ item.state }}" 8 | mode: "{{ item.mode }}" 9 | with_items: 10 | - { path: "/app", state: "directory", mode: "0755" } 11 | - { path: "/app/tmp", state: "directory", mode: "0755" } 12 | -------------------------------------------------------------------------------- /provision/roles/samson-deployment/tasks/build/ssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include_vars: /app/provision.yml 4 | 5 | - file: 6 | path: /home/application/.ssh 7 | owner: "{{ APPLICATION_USER }}" 8 | group: "{{ APPLICATION_GROUP }}" 9 | state: directory 10 | mode: 0700 11 | 12 | - name: Fix ssh owner 13 | command: find /home/application/.ssh -exec chown "{{ APPLICATION_USER }}:{{ APPLICATION_GROUP }}" {} \; 14 | 15 | - name: Fix ssh directory permissions 16 | command: find /home/application/.ssh -type d -exec chmod 0700 {} \; 17 | 18 | - name: Fix ssh file permissions 19 | command: find /home/application/.ssh -type f -exec chmod 0600 {} \; 20 | 21 | - file: 22 | path: /home/application/.ssh/known_hosts 23 | owner: "{{ APPLICATION_USER }}" 24 | group: "{{ APPLICATION_GROUP }}" 25 | state: touch 26 | mode: 0644 27 | 28 | - name: Save ssh fingerprints from known hosts (online) 29 | shell: ssh-keyscan -p "{{ item.port | default(22) }}" {{ item.opts | default() }} -H "{{ item.hostname }}" >> /home/application/.ssh/known_hosts 30 | with_items: "{{ SSH.known_hosts }}" 31 | when: SSH.known_hosts is defined and (item.file is not defined or item.file == "") 32 | 33 | - name: Save ssh fingerprints from known hosts (prefeched) 34 | shell: cat "/root/.known_ssh_prefetched/{{ item.file }}" >> /home/application/.ssh/known_hosts 35 | with_items: "{{ SSH.known_hosts }}" 36 | when: SSH.known_hosts is defined and (item.file is defined and item.file != "") 37 | -------------------------------------------------------------------------------- /provision/roles/samson-deployment/tasks/build/storage.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create storage directories 4 | file: 5 | path: "{{ item }}" 6 | owner: "{{ APPLICATION_USER }}" 7 | group: "{{ APPLICATION_GROUP }}" 8 | state: directory 9 | mode: 0755 10 | with_items: 11 | - /storage 12 | - /storage/db 13 | - /storage/cached_repos 14 | - /storage/build_cache 15 | - /storage/build_cache/npm 16 | - /storage/build_cache/composer 17 | 18 | - file: 19 | path: "{{ item }}" 20 | state: absent 21 | with_items: 22 | - /app/cached_repos 23 | 24 | - name: Link caching directories to /storage 25 | file: 26 | src: "{{ item.src }}" 27 | dest: "{{ item.dest }}" 28 | state: link 29 | force: yes 30 | with_items: 31 | - { src: "/storage/build_cache/composer", dest: "/home/application/.composer" } 32 | - { src: "/storage/build_cache/npm", dest: "/home/application/.npm" } 33 | - { src: "/storage/cached_repos", dest: "/app/cached_repos" } 34 | 35 | -------------------------------------------------------------------------------- /provision/roles/samson-deployment/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - include: build.yml 4 | tags: 5 | - build 6 | -------------------------------------------------------------------------------- /ssh/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webdevops/samson-deployment/5035f72ebd4cc899b452ecb8dc873fbe60885c7e/ssh/.gitkeep -------------------------------------------------------------------------------- /ssh/config: -------------------------------------------------------------------------------- 1 | ######################## 2 | ## Default 3 | ######################## 4 | 5 | Host * 6 | Compression yes 7 | CompressionLevel 6 8 | TCPKeepAlive yes 9 | KeepAlive yes 10 | ServerAliveInterval 60 11 | ForwardAgent no 12 | BatchMode yes 13 | 14 | ######################## 15 | ## Server 16 | ######################## -------------------------------------------------------------------------------- /ssh/known_hosts: -------------------------------------------------------------------------------- 1 | |1|emHzrzVUn4X4a6LNoOpxK7wBW1A=|eqw6DduGz9wQqwJbC3b94ATE1pw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== 2 | |1|QcmEj7cYWAopHnJx6Cjdde9e5Zw=|zfRGh6Dn92nEElLMTA11CT9olDs= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== --------------------------------------------------------------------------------