Herkese merhaba!

Uzun yıllardır bol miktarda kişisel zaman ve enerji harcayarak bilgimizi hepinizle paylaşıyoruz. Ancak şu andan itibaren bu blogu çalışır durumda tutabilmek için yardımınıza ihtiyacımız var. Yapmanız gereken tek şey, sitedeki reklamlardan birine tıklamak olacaktır, aksi takdirde hosting vb. masraflar nedeniyle maalesef yayından kaldırılacaktır. Teşekkürler.

Bu örneğimizde Ansible ve Jenkins kullanarak Docker üzerine kurulu olan Symfony uygulamamızı prodüksiyon ortamına ileteceğiz. Prodüksiyon ortamıyla çalışmak söz konusu olduğunda işler biraz zor olabilir, bu nedenle Docker ile ilgili dosyalar ve diğer kurulum dosyaları, geliştirme ortamına nazaran biraz farklı olurlar. Aşağıda farklılıkları göreceksiniz.


Jenkins sunucusu için şartlar


Aşağıdaki hususlara dikkat ettiğinizden emin olun.



Prodüksiyon ve Jenkins sunucu bilgileri aşağıdaki gibidir.



Ayrıca aşağıda detayları verilen bir MySQL sunucumuz (bir docker konteyner) de var.


DB_VERS=5.7.24
DB_HOST=192.168.99.20
DB_PORT=3306
DB_NAME=sport
DB_USER=inanzzz
DB_PASS=123123

Prodüksiyon sunucusu için şartlar


SSH GitHub entegrasyonunu hazırlayın ve docker komutunun çalıştırılabilirliğine emin olun.


Akış


Jenkins ve GitHub entegrasyonu kurulduğundan, bir PR'yi master dalıyla birleştirdiğimde, GitHub dağıtım hattının çalıştığı Jenkins ile iletişim kurar.


Alternatif: Bu örnek uygulamayı prodüksiyon sunucusuna klonlamak ve docker imaj/konteyner oluşturmak için, git işlevini kullanır. Ancak, uygulamayı konteyner imajına kopyalamayı tercih ediyorsanız ve uygulama klonlama adımlarını ortadan kaldırmak isterseniz bu yazıyı okuyabilirsiniz. Bu durumda Jenkinsfile, imajları Docker Hub'a itmek ve geri çekmek için biraz değişir. Daha sonra, yeni bir adımın docker dosyalarını prodüksiyon sunucusuna kopyalayıp docker pull/build/up komutlarını çalıştırması gerekir.


  1. Jenkins master dalına geçer.

  2. Ansible SSH ile prodüksiyon sunucusuna bağlanıp iletim işlemini başlatır.

    1. Uygulama klasörü yaratılır.

    2. Uygulama klonlanır.

    3. Vault ile şifrelenmiş .env dosyası kopyalanır.

    4. Uygulama çalıştırılır.

    5. secure-delete paketi kurulur.

    6. Kopyalanan her şey silinir.

MySQL sunucusu için şartlar


Aşağıdaki adımlar bir defaya mahsustur ve her şeyden önce yapılması gerekir.


Dış bağlantılara izin verme


bind-address girdisini aşağıdaki gibi değiştirin.


mysql-server$ cat /etc/mysql/my.cnf | grep bind-address
#bind-address = 127.0.0.1
bind-address = 0.0.0.0

MySQL sunucusuna mysql-server$ mysql -u root -proot komutu ile bağlanıp aşağıdaki komutları çalıştırın.


Yeni veritabanı ve izinleri olan kullanıcı


sport isminde yeni bir veritabanı yaratın.


mysql> CREATE DATABASE `sport` CHARACTER SET `UTF8mb4` COLLATE `utf8mb4_unicode_ci`;

mysql> SHOW databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sport |
+--------------------+

inanzzz isminde yeni bir kullanıcı yaratın ve sport veritabanı kullanımı için tüm izinleri verin.


mysql> USE mysql;

mysql> CREATE USER 'inanzzz'@'%' IDENTIFIED BY '123123';
mysql> GRANT ALL PRIVILEGES ON sport.* TO 'inanzzz'@'%' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;

mysql> SELECT user, host FROM user;
+------------------+-----------+
| user | host |
+------------------+-----------+
| inanzzz | % |
| root | 127.0.0.1 |
| root | ::1 |
| root | localhost |
+------------------+-----------+

mysql> SHOW GRANTS FOR 'inanzzz'@'%';
+--------------------------------------------------------------------------------------------------------+
| Grants for inanzzz@% |
+--------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'inanzzz'@'%' IDENTIFIED BY PASSWORD '*E56A114692FE0DE073F9A1DD68A00EEB9703F3F1' |
| GRANT ALL PRIVILEGES ON `sport`.* TO 'inanzzz'@'%' WITH GRANT OPTION |
+--------------------------------------------------------------------------------------------------------+

Yapı


Aşağıda dev ortamının dosyalarınıda listeleyeceğim. Bu size prod ortamının dosyalarına göre ne tür değişiklikler olduğunu gösterecektir. Kayda değer farklılıklar Dockerfile, Makefile ve docker-compose.yml dosyaları için geçerlidir.


.
├── bin
│   └── ...
├── cicd
│   ├── merge
│   │   └── master
│   │   └── Jenkinsfile
│   └── provision
│   └── prod
│   ├── hosts.yml
│   └── site.yml
├── composer.json
├── composer.lock
├── config
│   └── ...
├── docker
│   ├── dev
│   │   ├── docker-compose.yml
│   │   ├── Makefile
│   │   ├── nginx
│   │   │   ├── app.conf
│   │   │   ├── Dockerfile
│   │   │   └── nginx.conf
│   │   └── php
│   │   ├── Dockerfile
│   │   ├── php.ini
│   │   └── www.conf
│   └── prod
│   ├── docker-compose.yml
│   ├── Makefile
│   ├── nginx
│   │   ├── app.conf
│   │   ├── Dockerfile
│   │   └── nginx.conf
│   └── php
│      ├── Dockerfile
│      ├── php.ini
│      └── www.conf
├── .dockerignore
├── .env
├── .gitignore
├── public
│   └── ...
├── Readme.md
├── src
│   └── ...
├── symfony.lock
├── var
│   └── ...
└── vendor
   └── ...

Dev dosyaları


docker/dev/docker-compose.yml


version: "3.4"

services:

football_mysql:
image: "mysql:5.7.24"
hostname: "football-mysql"
command: "--default-authentication-plugin=mysql_native_password"
environment:
MYSQL_ROOT_PASSWORD: "root"
PS1: "\\u@\\h:\\w\\$$ "

football_php:
build:
context: "./php"
hostname: "football-php"
volumes:
- "../..:/app:consistent"
depends_on:
- "football_mysql"
environment:
PS1: "\\u@\\h:\\w\\$$ "
sysctls:
- "net.core.somaxconn=1000"

football_nginx:
build:
context: "./nginx"
hostname: "football-nginx"
ports:
- "1080:80"
volumes:
- "../..:/app:consistent"
depends_on:
- "football_mysql"
- "football_php"
environment:
PS1: "\\u@\\h:\\w\\$$ "

docker/dev/Makefile


PHP_SERVICE := football_php

build:
@docker-compose build

up:
@docker-compose up -d

composer:
@docker-compose exec -T $(PHP_SERVICE) composer install

database:
@docker-compose exec -T $(PHP_SERVICE) bin/console doctrine:database:create --if-not-exists
@docker-compose exec -T $(PHP_SERVICE) bin/console doctrine:migrations:migrate --no-interaction
@docker-compose exec -T $(PHP_SERVICE) bin/console doctrine:schema:validate

clean:
@docker-compose down
@docker system prune --volumes --force

config:
@docker-compose config

init:
@make build
@make up
@make composer
@make database

docker/dev/nginx/app.conf


server {
listen 80 default_server;

server_name localhost;

root /app/public;

location / {
try_files $uri /index.php$is_args$args;
}

location ~ ^/index\.php(/|$) {
fastcgi_pass football_php:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_hide_header X-Powered-By;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param HTTP_X_REQUEST_ID $request_id;
internal;
}

location ~ \.php$ {
return 404;
}

error_log /var/log/nginx/app_error.log;
access_log /var/log/nginx/app_access.log;
}

docker/dev/nginx/nginx.conf


user nginx;

worker_processes 2;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 2048;
use epoll;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
server_tokens off;

add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection '1; mode=block';
add_header X-Frame-Options DENY;
add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains; preload';
add_header 'Referrer-Policy' 'no-referrer-when-downgrade';

types_hash_max_size 2048;
gzip on;

include /etc/nginx/conf.d/*.conf;
}

docker/dev/nginx/Dockerfile


FROM nginx:1.15.8-alpine

RUN rm -rf /var/cache/apk/* \
/var/lib/apt/lists/*

COPY app.conf /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/nginx.conf

docker/dev/php/php.ini


[PHP]
date.timezone=UTC
log_errors=On
error_reporting=E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors=Off
max_execution_time=60
memory_limit=256M

[opcache]
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
realpath_cache_size=4096K
realpath_cache_ttl=600

docker/dev/php/www.conf


[global]
daemonize=no

[www]
user=www-data
group=www-data

listen=football_nginx:9000
listen.backlog=1000 # This is optional but important for production so read what I wrote to docker-compose.yml file section.

pm=dynamic
pm.max_children=40
pm.start_servers=2
pm.min_spare_servers=2
pm.max_spare_servers=4
pm.max_requests=500

docker/dev/php/Dockerfile


FROM php:7.2.13-fpm-alpine3.8

WORKDIR /app

RUN apk update \
&& apk add --no-cache $PHPIZE_DEPS \
git \
zip \
unzip \
&& docker-php-ext-install \
opcache \
pdo_mysql \
&& docker-php-ext-enable \
opcache \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& rm -rf \
/var/cache/apk/* \
/var/lib/apt/lists/*

COPY php.ini /usr/local/etc/php/conf.d/php.override.ini
COPY www.conf /usr/local/etc/php-fpm.d/www.conf

CMD ["php-fpm", "--nodaemonize"]

Prod dosyaları


docker/prod/docker-compose.yml


Her dağıtımda "adlandırılmış birim" için farklı bir ad kullanmazsak, uygulama kodunda yaptığımız değişiklikler prodüksiyon ortamında kullanılamaz. Bu nedenle Jenkins'ten gelen BUILD_ID ortam değişkenini adın sonuna ekliyorum. Ansible playbook bunu Makefile dosyasına, ardından Makefile ise docker-compose.yml dosyasına iletir. Ayrıca uygulama kodunu, Nginx servisinin "adlandırılmış birim" aracılığı ile kullanabilmesi için, football_php ismindeki "php container" içine kopyalıyorum.


Önemli not: Her ne kadar net.core.somaxconn mecburi olmasada, çok önemlidir. Bu, maksimum geri kazanılmış TCP/IP soketlerini belirten bir Linux Çekirdek parametresidir. Varsayılan değer 128'dir. Değişikliklerimize bakarsak, çekirdek bir kerede en fazla 1000 bağlantıyı sırada beklemeye alacaktır. Bu değer USHRT_MAX değişkeninin değerini (65535) geçemez. Aynı değer /usr/local/etc/php-fpm.d/www.conf dosyasındaki listen.backlog girdisi için de geçerlidir. PHP-FPM konteyner içinde sysctl net.core.somaxconn komutunu çalıştırarak kontrol edebilirsiniz. Kısacası, çok fazla eşzamanlı istek bekliyorsanız, değeri yüksek tutmak en iyisidir. Ben 10000:1000 (toplam:eşzamanlı) istek kullanarak $ ab -n 10000 -c 1000 http://0.0.0.0:80/ komutu ile test ettim ve sonuçta hepsi işlendi. Değeri 500 olarak ayarladığımda, ortalama 300 istek işlenemiyor. Bir diğer örnek ise, Redis genelde çok bağlantı aldığı için değerin yüksek olması faydalı olur.


version: "3.4"

services:

football_php:
build:
context: "../.."
dockerfile: "docker/prod/php/Dockerfile"
hostname: "football-php"
volumes:
- "source_code:/app:consistent"
environment:
PS1: "\\u@\\h:\\w\\$$ "
sysctls:
- "net.core.somaxconn=1000"
env_file:
- "../../.env"

football_nginx:
build:
context: "./nginx"
hostname: "football-nginx"
ports:
- "80:80"
volumes:
- "source_code:/app:consistent"
depends_on:
- "football_php"
environment:
PS1: "\\u@\\h:\\w\\$$ "

volumes:
source_code:
name: "football_source_code_${BUILD_ID}"

docker/prod/Makefile


build:
@docker-compose build

up:
@docker-compose up -d

clean:
@docker system prune --volumes --force

config:
@docker-compose config

init:
@make build
@make up
@make clean

docker/prod/nginx/app.conf


SSL sertifika ve port 443 ayarlarını, benim burada yaptığım gibi prodüksiyon ortamında önemsememezlik yapmayın!


server {
listen 80 default_server;

server_name localhost;

root /app/public;

location / {
try_files $uri /index.php$is_args$args;
}

location ~ ^/index\.php(/|$) {
fastcgi_pass football_php:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_hide_header X-Powered-By;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param HTTP_X_REQUEST_ID $request_id;
internal;
}

location ~ \.php$ {
return 404;
}

error_log /var/log/nginx/app_error.log;
access_log /var/log/nginx/app_access.log;
}

docker/prod/nginx/nginx.conf


user nginx;

worker_processes 2;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 2048;
use epoll;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
server_tokens off;

add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection '1; mode=block';
add_header X-Frame-Options DENY;
add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains; preload';
add_header 'Referrer-Policy' 'no-referrer-when-downgrade';

types_hash_max_size 2048;
gzip on;

include /etc/nginx/conf.d/*.conf;
}

docker/prod/nginx/Dockerfile


FROM nginx:1.15.8-alpine

WORKDIR /app

RUN rm -rf /var/cache/apk/* \
/var/lib/apt/lists/*

COPY app.conf /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/nginx.conf

docker/prod/php/php.ini


[PHP]
date.timezone=UTC
log_errors=On
error_reporting=E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors=Off
max_execution_time=60
memory_limit=256M

[opcache]
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
realpath_cache_size=4096K
realpath_cache_ttl=600

docker/prod/php/www.conf


[global]
daemonize=no

[www]
user=www-data
group=www-data

listen=football_nginx:9000
listen.backlog=1000 # This is optional but important for production so read what I wrote to docker-compose.yml file section.

pm=dynamic
pm.max_children=40
pm.start_servers=2
pm.min_spare_servers=2
pm.max_spare_servers=4
pm.max_requests=500

docker/prod/php/Dockerfile


FROM php:7.2.13-fpm-alpine3.8

WORKDIR /app

RUN apk update \
&& apk add --no-cache $PHPIZE_DEPS \
git \
zip \
unzip \
&& docker-php-ext-install \
opcache \
pdo_mysql \
&& docker-php-ext-enable \
opcache \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& rm -rf \
/var/cache/apk/* \
/var/lib/apt/lists/*

COPY . /app

COPY docker/prod/php/php.ini /usr/local/etc/php/conf.d/php.override.ini
COPY docker/prod/php/www.conf /usr/local/etc/php-fpm.d/www.conf

RUN set -xe \
&& composer install --no-dev --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader \
&& composer dump-autoload --no-dev --optimize --classmap-authoritative \
&& bin/console cache:clear \
&& bin/console cache:warm \
&& bin/console doctrine:migrations:migrate --no-interaction

CMD ["php-fpm", "--nodaemonize"]

CICD dosyaları


cicd/merge/master/Jenkinsfile


pipeline {
agent any

options {
skipDefaultCheckout(true)
}

stages {
stage('Git') {
steps {
echo '> Checking out the Git version control ...'
checkout scm
}
}
stage('Deploy') {
steps {
echo '> Deploying the application ...'
ansiblePlaybook(
vaultCredentialsId: 'AnsibleVault',
inventory: 'cicd/provision/prod/hosts.yml',
playbook: 'cicd/provision/prod/site.yml'
)
}
}
}
}

cicd/provision/prod/hosts.yml


İsterseniz bunu Ansible vault ile şifreleyebilirsiniz.


all:
hosts:
production:
ansible_connection: ssh
ansible_user: vagrant
ansible_host: 192.168.99.30
ansible_port: 22

cicd/provision/prod/site.yml


İsterseniz MySQL sunucusunu burada hazırlayabilir ve bazı ortam değişkenlerini kullanabilirsiniz.


---
# All tasks below are run in "production" server.

- name: Deploy application to the "production" server
hosts: production
remote_user: vagrant
become: yes
tasks:

- name: Create application directory
file:
path: /home/vagrant/football
state: directory
owner: vagrant
group: vagrant

- name: Clone application repository
git:
repo: git@github.com:inanzzz/football.git
dest: /home/vagrant/football
clone: yes
force: yes
recursive: yes
version: master
accept_hostkey: yes
key_file: /home/vagrant/.ssh/id_rsa
become_user: vagrant

- name: Copy secret .env file over
copy:
src: /var/lib/jenkins/app-secrets/sport/.env
dest: /home/vagrant/football/.env
owner: vagrant
group: vagrant
no_log: true

- name: Bring application up
make:
chdir: /home/vagrant/football/docker/prod
target: init
params:
BUILD_ID: "{{ lookup('env','BUILD_ID') }}"

- name: Install "secure-delete" package
apt:
name: secure-delete
state: present

- name: Secure deleting application folder
command: srm -vzr /home/vagrant/football

Diğer dosyalar


.dockerignore


cicd/
config/packages/dev/
config/packages/test/
docker/dev/
var/
vendor/
.dockerignore
.gitignore
Readme.md

.git/
.idea/
.DS_Store/

.env


APP_ENV=dev
APP_SECRET=1c29c11fe70df5af758f775c6e3d03ef
DB_HOST=football_mysql
DB_PORT=3306
DB_NAME=football
DB_USER=root
DB_PASS=root
DB_VERS=5.7.24

config/packages/doctrine.yaml


doctrine:
dbal:
host: '%env(string:DB_HOST)%'
port: '%env(int:DB_PORT)%'
dbname: '%env(string:DB_NAME)%'
user: '%env(string:DB_USER)%'
password: '%env(string:DB_PASS)%'
driver: 'pdo_mysql'
server_version: '%env(string:DB_VERS)%'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
orm:
...

DefaultContainer.php


class EnvironmentController
{
private $envFile;

public function __construct(
string $envFile # This refers to .env fine in the project root
) {
$this->envFile = $envFile;
}

public function index(): Response
{
$envFile = file_get_contents($this->envFile);

echo trim($envFile).PHP_EOL;
echo '------------------------------------------'.PHP_EOL;
foreach (['APP_ENV', 'APP_SECRET', 'DB_VERS', 'DB_HOST', 'DB_PORT', 'DB_NAME', 'DB_USER', 'DB_PASS'] as $env) {
echo $env.':'.getenv($env).PHP_EOL;
}
echo '------------------------------------------'.PHP_EOL;
print_r($_ENV);

return new Response();
}
}

Ansible Vault şifreleme


Prodüksiyon ortamının .env dosyası gizli/önemli değerler içeriyor, bu nedenle Jenkins sunucusunda oluşturmamız ve ansible-vault komutuyla şifrelememiz gerekiyor. İletim başladığında, arka planda (stage('Deploy') aşamasında) şifresi çözülür ve prodüksiyon sunucusuna aktarılır. Değerler php konteyner ortam değişkenleri olarak ayarlanacak ve Symfony uygulamamız bunları .env dosyasında ayarlanan değişkenler yerine kullanacak. Çevre değişkenleri her zaman önceliğe sahiptir!


jenkins@jenkins-server:$ mkdir -p ~/app-secrets/sport
jenkins@jenkins-server:$ ansible-vault create ~/app-secrets/sport/.env
New Vault password: # the password is same as the one set in Jenkins credentials section
Confirm New Vault password: # repeat

jenkins@jenkins-server:$ cat ~/app-secrets/sport/.env
$ANSIBLE_VAULT;1.1;AES256
31396662396139623232346537373466616234636535373534333061353766313263623035313833
3436356166613638343366663933623137343833373134660a663334333139393632653233656333
66626333623134623066663565323761323934663835376439333231313733363636633539393630
6164326464646337360a353133666335303734303532623866613633623932613737616635383631
39666432626562383932363363326664306636356236666136353661356632613337333762323166
63653234613536616432663363373265393732313035333461396533336539373638666561633135
31316430633266356562313362366564343935313231383561336636656133666561366239343638
63396364636436353932313638653532336335643737383436623737356637636136646239323831
37363639363964623762303361383738303436313133643333653063333239663630613566626135
36306130346331633931373439633632653930656137303261633339316335656539613536643933
66393830393263323266656634646465306338383062386535393538363964646561353533313239
32383538356439613030313134653861393161363639643835633564313137656566623638366534
3632

Gerçek içerik aşağıda gösterilmiştir.


APP_ENV=prod
APP_SECRET=91f6e527cdd2e73e929a6aaaea8036c630b025a7
DB_VERS=5.7.24
DB_HOST=192.168.99.20
DB_PORT=3306
DB_NAME=sport
DB_USER=inanzzz
DB_PASS=123123

Prodüksiyon hattının test edilmesi


Bir PR'yi master ile birleştirdiğimizi varsayın.


Running on Jenkins in /var/lib/jenkins/workspace/sport-merge-master

[Pipeline] Start of Pipeline
> Checking out the Git version control ...
using GIT_SSH to set credentials
Checking out Revision 11d8e7e0a0584ue4112d4b37ee2f0a2df18abar5 (origin/master)

> Deploying the application ...
[football-merge-master] $ ansible-playbook cicd/provision/prod/site.yml
-i cicd/provision/prod/hosts.yml
--vault-password-file /var/lib/jenkins/workspace/football-merge-master/vault2614692457220871566.password

PLAY [Deploy application to the "production" server] ***************************

TASK [Gathering Facts] *********************************************************
ok: [production]

TASK [Create application directory] ********************************************
changed: [production]

TASK [Clone application repository] ********************************************
changed: [production]

TASK [Copy secret .env file over] **********************************************
changed: [production]

TASK [Bring application up] ****************************************************
changed: [production]

TASK [Install "secure-delete" package] *****************************************
ok: [production]

TASK [Secure deleting application folder] **************************************
changed: [production]

PLAY RECAP *********************************************************************
production : ok=7 changed=5 unreachable=0 failed=0

[Pipeline] End of Pipeline
Finished: SUCCESS


Prodüksiyon sunucusunu kontrol etme


Gördüğünüz gibi başlangıçta yarattığımız /home/vagrant/sport dağıtım işleminin sonunda silindi.


vagrant@production:~$ ls -l
total 0

vagrant@production:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
prod_football_php latest 17ebe027a0cb 34 minutes ago 310MB
prod_football_nginx latest f997f8d3c442 About an hour ago 16.1MB
nginx 1.15.8-alpine b411e34b4606 3 months ago 16.1MB
mysql 5.7.24 ba7a93aae2a8 4 months ago 372MB
php 7.2.13-fpm-alpine3.8 262e46e3d43c 5 months ago 77.7MB

vagrant@production:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aae23b67b036 prod_football_nginx "nginx -g 'daemon of…" 35 minutes ago Up 35 minutes 0.0.0.0:80->80/tcp prod_football_nginx_1
d201791f9b9b prod_football_php "docker-php-entrypoi…" 35 minutes ago Up 35 minutes 9000/tcp prod_football_php_1

vagrant@production:~$ docker volume ls
DRIVER VOLUME NAME
local football_source_code_17

vagrant@production:~$ docker inspect football_source_code_17
[
{
"CreatedAt": "2019-05-25T17:11:37+01:00",
"Driver": "local",
"Labels": {
"com.docker.compose.project": "prod",
"com.docker.compose.version": "1.21.2",
"com.docker.compose.volume": "football_source_code_17"
},
"Mountpoint": "/var/lib/docker/volumes/football_source_code_17/_data",
"Name": "football_source_code_17",
"Options": null,
"Scope": "local"
}
]

vagrant@production:~$ sudo ls -l /var/lib/docker/volumes/football_source_code_17/_data
drwxr-xr-x 2 root root 4096 May 25 17:11 bin
-rw-r--r-- 1 root root 1444 May 25 17:10 composer.json
-rw-r--r-- 1 root root 118858 May 25 17:10 composer.lock
drwxr-xr-x 4 root root 4096 May 25 17:11 config
drwxr-xr-x 3 root root 4096 May 25 17:11 docker
drwxr-xr-x 2 root root 4096 May 25 17:11 public
drwxr-xr-x 8 root root 4096 May 25 17:11 src
-rw-r--r-- 1 root root 5998 May 25 17:10 symfony.lock
drwxr-xr-x 4 root root 4096 May 25 17:11 var
drwxr-xr-x 11 root root 4096 May 25 17:11 vendor

Uygulama kontrolü


vagrant@production:~$ curl -i http://0.0.0.0:80 # or http://0.0.0.0 | http://localhost
# or from outside with http://192.168.99.30

APP_ENV=prod
APP_SECRET=91f6e527cdd2e73e929a6aaaea8036c630b025a7
DB_VERS=5.7.24
DB_HOST=192.168.99.20
DB_PORT=3306
DB_NAME=sport
DB_USER=inanzzz
DB_PASS=123123
------------------------------------------
APP_ENV:prod
APP_SECRET:91f6e527cdd2e73e929a6aaaea8036c630b025a7
DB_VERS:5.7.24
DB_HOST:192.168.99.20
DB_PORT:3306
DB_NAME:sport
DB_USER:inanzzz
DB_PASS:123123
------------------------------------------
Array
(
[PHP_EXTRA_CONFIGURE_ARGS] => --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data --disable-cgi
[HOSTNAME] => football-php
[DB_PORT] => 3306
[PHP_INI_DIR] => /usr/local/etc/php
[SHLVL] => 1
[HOME] => /home/www-data
[DB_NAME] => sport
[PS1] => \u@\h:\w\$
[PHP_LDFLAGS] => -Wl,-O1 -Wl,--hash-style=both -pie
[PHP_CFLAGS] => -fstack-protector-strong -fpic -fpie -O2
[PHP_MD5] =>
[PHP_VERSION] => 7.2.13
[GPG_KEYS] => 1729F83938DA44E27BA0F4D3DBDB397470D12172 B1B44D8F021E4E2D6021E995DC9FF8D3EE5AF27F
[PHP_CPPFLAGS] => -fstack-protector-strong -fpic -fpie -O2
[PHP_ASC_URL] => https://secure.php.net/get/php-7.2.13.tar.xz.asc/from/this/mirror
[PHP_URL] => https://secure.php.net/get/php-7.2.13.tar.xz/from/this/mirror
[APP_SECRET] => 91f6e527cdd2e73e929a6aaaea8036c630b025a7
[PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[DB_PASS] => 123123
[APP_ENV] => prod
[PHPIZE_DEPS] => autoconf dpkg-dev dpkg file g++ gcc libc-dev make pkgconf re2c
[PWD] => /app
[PHP_SHA256] => 14b0429abdb46b65c843e5882c9a8c46b31dfbf279c747293b8ab950c2644a4b
[DB_HOST] => 192.168.99.20
[DB_USER] => inanzzz
[DB_VERS] => 5.7.24
[USER] => www-data
[HTTP_ACCEPT] => */*
[HTTP_HOST] => 0.0.0.0
[HTTP_USER_AGENT] => curl/7.38.0
[HTTP_X_REQUEST_ID] => a9fa864522fa78ee7b3ffb5ec1ddf730
[SCRIPT_FILENAME] => /app/public/index.php
[REDIRECT_STATUS] => 200
[SERVER_NAME] => localhost
[SERVER_PORT] => 80
[SERVER_ADDR] => 172.19.0.4
[REMOTE_PORT] => 43109
[REMOTE_ADDR] => 172.19.0.1
[SERVER_SOFTWARE] => nginx/1.15.8
[GATEWAY_INTERFACE] => CGI/1.1
[REQUEST_SCHEME] => http
[SERVER_PROTOCOL] => HTTP/1.1
[DOCUMENT_ROOT] => /app/public
[DOCUMENT_URI] => /index.php
[REQUEST_URI] => /env
[SCRIPT_NAME] => /index.php
[CONTENT_LENGTH] =>
[CONTENT_TYPE] =>
[REQUEST_METHOD] => GET
[QUERY_STRING] =>
[FCGI_ROLE] => RESPONDER
[PHP_SELF] => /index.php
[REQUEST_TIME_FLOAT] => 1558803124.4202
[REQUEST_TIME] => 1558803124
[argv] => Array
(
)

[argc] => 0
[APP_DEBUG] => 0
)