diff --git a/ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml b/ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml
new file mode 100644
index 0000000000..a3f8cd9549
--- /dev/null
+++ b/ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml
@@ -0,0 +1,22 @@
+plugin: aws_ec2
+regions:
+ - "us-east-1"
+filters:
+ tag:app-stack-name: APP_STACK_NAME
+ tag:environment: dev
+keyed_groups:
+ - key: tags['app-stack-name']
+ prefix: 'app_stack_'
+ separator: ''
+ - key: tags['swarm-role']
+ prefix: 'role_'
+ separator: ''
+ - key: tags['environment']
+ prefix: 'env_'
+ separator: ''
+ - key: tags['server']
+ separator: ''
+hostnames:
+ - "private-ip-address"
+compose:
+ ansible_user: "'ec2-user'"
\ No newline at end of file
diff --git a/ansible/inventory/dev_stack_swarm_grand_master_aws_ec2.yaml b/ansible/inventory/dev_stack_swarm_grand_master_aws_ec2.yaml
new file mode 100644
index 0000000000..b1569ff1d9
--- /dev/null
+++ b/ansible/inventory/dev_stack_swarm_grand_master_aws_ec2.yaml
@@ -0,0 +1,11 @@
+plugin: aws_ec2
+regions:
+ - "us-east-1"
+filters:
+ tag:app-stack-name: APP_STACK_NAME
+ tag:environment: dev
+ tag:swarm-role: grand-master
+hostnames:
+ - "private-ip-address"
+compose:
+ ansible_user: "'ec2-user'"
\ No newline at end of file
diff --git a/ansible/inventory/dev_stack_swarm_managers_aws_ec2.yaml b/ansible/inventory/dev_stack_swarm_managers_aws_ec2.yaml
new file mode 100644
index 0000000000..e9647b593b
--- /dev/null
+++ b/ansible/inventory/dev_stack_swarm_managers_aws_ec2.yaml
@@ -0,0 +1,11 @@
+plugin: aws_ec2
+regions:
+ - "us-east-1"
+filters:
+ tag:app-stack-name: APP_STACK_NAME
+ tag:environment: dev
+ tag:swarm-role: manager
+hostnames:
+ - "private-ip-address"
+compose:
+ ansible_user: "'ec2-user'"
\ No newline at end of file
diff --git a/ansible/inventory/dev_stack_swarm_workers_aws_ec2.yaml b/ansible/inventory/dev_stack_swarm_workers_aws_ec2.yaml
new file mode 100644
index 0000000000..f702f7ad93
--- /dev/null
+++ b/ansible/inventory/dev_stack_swarm_workers_aws_ec2.yaml
@@ -0,0 +1,11 @@
+plugin: aws_ec2
+regions:
+ - "us-east-1"
+filters:
+ tag:app-stack-name: APP_STACK_NAME
+ tag:environment: dev
+ tag:swarm-role: worker
+hostnames:
+ - "private-ip-address"
+compose:
+ ansible_user: "'ec2-user'"
\ No newline at end of file
diff --git a/ansible/inventory/hosts.ini b/ansible/inventory/hosts.ini
new file mode 100644
index 0000000000..cd3534ffd5
--- /dev/null
+++ b/ansible/inventory/hosts.ini
@@ -0,0 +1,5 @@
+172.31.18.79 ansible_user=ec2-user
+172.31.17.104 ansible_user=ec2-user
+172.31.82.199 ansible_user=ec2-user
+172.31.27.10 ansible_user=ec2-user
+172.31.83.29 ansible_user=ec2-user
\ No newline at end of file
diff --git a/ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml b/ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml
new file mode 100644
index 0000000000..ea26604c19
--- /dev/null
+++ b/ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml
@@ -0,0 +1,22 @@
+plugin: aws_ec2
+regions:
+ - "us-east-1"
+filters:
+ tag:app-stack-name: APP_STACK_NAME
+ tag:environment: qa
+keyed_groups:
+ - key: tags['app-stack-name']
+ prefix: 'app_stack_'
+ separator: ''
+ - key: tags['swarm-role']
+ prefix: 'role_'
+ separator: ''
+ - key: tags['environment']
+ prefix: 'env_'
+ separator: ''
+ - key: tags['server']
+ separator: ''
+hostnames:
+ - "private-ip-address"
+compose:
+ ansible_user: "'ec2-user'"
\ No newline at end of file
diff --git a/ansible/playbooks/pb_deploy_app_on_docker_swarm.yaml b/ansible/playbooks/pb_deploy_app_on_docker_swarm.yaml
new file mode 100644
index 0000000000..fe81737bbc
--- /dev/null
+++ b/ansible/playbooks/pb_deploy_app_on_docker_swarm.yaml
@@ -0,0 +1,14 @@
+---
+- hosts: role_grand_master
+ tasks:
+ - name: Copy docker compose file to grand master
+ copy:
+ src: "{{ workspace }}/docker-compose-swarm-dev-tagged.yml"
+ dest: /home/ec2-user/docker-compose-swarm-dev-tagged.yml
+ - name: get login credentials for ecr
+ shell: "export PATH=$PATH:/usr/local/bin/ && aws ecr get-login-password --region {{ aws_region }} | docker login --username AWS --password-stdin {{ ecr_registry }}"
+ register: output
+ - name: deploy the app stack on swarm
+ shell: "docker stack deploy --with-registry-auth -c /home/ec2-user/docker-compose-swarm-dev-tagged.yml {{ app_name }}"
+ register: output
+ - debug: msg="{{ output.stdout }}"
\ No newline at end of file
diff --git a/ansible/playbooks/pb_deploy_app_on_qa_environment.yaml b/ansible/playbooks/pb_deploy_app_on_qa_environment.yaml
new file mode 100644
index 0000000000..c1a1711de2
--- /dev/null
+++ b/ansible/playbooks/pb_deploy_app_on_qa_environment.yaml
@@ -0,0 +1,14 @@
+---
+- hosts: role_grand_master
+ tasks:
+ - name: Copy docker compose file to grand master
+ copy:
+ src: "{{ workspace }}/docker-compose-swarm-qa-tagged.yml"
+ dest: /home/ec2-user/docker-compose-swarm-qa-tagged.yml
+ - name: get login credentials for ecr
+ shell: "export PATH=$PATH:/usr/local/bin/ && aws ecr get-login-password --region {{ aws_region }} | docker login --username AWS --password-stdin {{ ecr_registry }}"
+ register: output
+ - name: deploy the app stack on swarm
+ shell: "docker stack deploy --with-registry-auth -c /home/ec2-user/docker-compose-swarm-qa-tagged.yml {{ app_name }}"
+ register: output
+ - debug: msg="{{ output.stdout }}"
\ No newline at end of file
diff --git a/ansible/playbooks/pb_initialize_docker_swarm.yaml b/ansible/playbooks/pb_initialize_docker_swarm.yaml
new file mode 100644
index 0000000000..e1a9c473fc
--- /dev/null
+++ b/ansible/playbooks/pb_initialize_docker_swarm.yaml
@@ -0,0 +1,13 @@
+---
+- hosts: role_grand_master
+ tasks:
+ - name: initialize docker swarm
+ shell: docker swarm init
+ - name: run the visualizer app for docker swarm
+ shell: |
+ docker service create \
+ --name=viz \
+ --publish=8088:8080/tcp \
+ --constraint=node.role==manager \
+ --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
+ dockersamples/visualizer
\ No newline at end of file
diff --git a/ansible/playbooks/pb_join_docker_swarm_managers.yaml b/ansible/playbooks/pb_join_docker_swarm_managers.yaml
new file mode 100644
index 0000000000..b9ac69c7c3
--- /dev/null
+++ b/ansible/playbooks/pb_join_docker_swarm_managers.yaml
@@ -0,0 +1,17 @@
+---
+- hosts: role_grand_master
+ tasks:
+ - name: Get swarm join-token for managers
+ shell: docker swarm join-token manager | grep -i 'docker'
+ register: join_command_for_managers
+ - debug: msg='{{ join_command_for_managers.stdout.strip() }}'
+ - name: register grand_master with variable
+ add_host:
+ name: "grand_master"
+ manager_join: "{{ join_command_for_managers.stdout.strip() }}"
+- hosts: role_manager
+ tasks:
+ - name: Join managers to swarm
+ shell: "{{ hostvars['grand_master']['manager_join'] }}"
+ register: result_of_joining
+ - debug: msg='{{ result_of_joining.stdout }}'
\ No newline at end of file
diff --git a/ansible/playbooks/pb_join_docker_swarm_workers.yaml b/ansible/playbooks/pb_join_docker_swarm_workers.yaml
new file mode 100644
index 0000000000..19df5e03f7
--- /dev/null
+++ b/ansible/playbooks/pb_join_docker_swarm_workers.yaml
@@ -0,0 +1,17 @@
+---
+- hosts: role_grand_master
+ tasks:
+ - name: Get swarm join-token for workers
+ shell: docker swarm join-token worker | grep -i 'docker'
+ register: join_command_for_workers
+ - debug: msg='{{ join_command_for_workers.stdout.strip() }}'
+ - name: register grand_master with variable
+ add_host:
+ name: "grand_master"
+ worker_join: "{{ join_command_for_workers.stdout.strip() }}"
+- hosts: role_worker
+ tasks:
+ - name: Join workers to swarm
+ shell: "{{ hostvars['grand_master']['worker_join'] }}"
+ register: result_of_joining
+ - debug: msg='{{ result_of_joining.stdout }}'
\ No newline at end of file
diff --git a/ansible/playbooks/pb_run_dummy_selenium_job.yaml b/ansible/playbooks/pb_run_dummy_selenium_job.yaml
new file mode 100644
index 0000000000..9585026caa
--- /dev/null
+++ b/ansible/playbooks/pb_run_dummy_selenium_job.yaml
@@ -0,0 +1,10 @@
+---
+- hosts: all
+ tasks:
+ - name: run dummy selenium job
+ shell: "docker run --rm -v {{ workspace }}:{{ workspace }} -w {{ workspace }} callahanclarus/selenium-py-chrome:latest python {{ item }}"
+ with_fileglob: "{{ workspace }}/selenium-jobs/dummy*.py"
+ register: output
+ - name: show results
+ debug: msg="{{ item.stdout }}"
+ with_items: "{{ output.results }}"
\ No newline at end of file
diff --git a/ansible/playbooks/pb_run_selenium_jobs.yaml b/ansible/playbooks/pb_run_selenium_jobs.yaml
new file mode 100644
index 0000000000..3c76d89025
--- /dev/null
+++ b/ansible/playbooks/pb_run_selenium_jobs.yaml
@@ -0,0 +1,10 @@
+---
+- hosts: all
+ tasks:
+ - name: run all selenium jobs
+ shell: "docker run --rm --env MASTER_PUBLIC_IP={{ master_public_ip }} -v {{ workspace }}:{{ workspace }} -w {{ workspace }} callahanclarus/selenium-py-chrome:latest python {{ item }}"
+ register: output
+ with_fileglob: "{{ workspace }}/selenium-jobs/test*.py"
+ - name: show results
+ debug: msg="{{ item.stdout }}"
+ with_items: "{{ output.results }}"
\ No newline at end of file
diff --git a/ansible/playbooks/pb_setup_for_all_docker_swarm_instances.yaml b/ansible/playbooks/pb_setup_for_all_docker_swarm_instances.yaml
new file mode 100644
index 0000000000..d4d401cd1c
--- /dev/null
+++ b/ansible/playbooks/pb_setup_for_all_docker_swarm_instances.yaml
@@ -0,0 +1,53 @@
+---
+- hosts: all
+ tasks:
+ - name: update os
+ yum:
+ name: '*'
+ state: present
+ - name: install docker
+ command: amazon-linux-extras install docker=latest -y
+ - name: start docker
+ service:
+ name: docker
+ state: started
+ enabled: yes
+ - name: add ec2-user to docker group
+ shell: "usermod -a -G docker ec2-user"
+ - name: Install Docker Compose (if configured).
+ get_url:
+ url: https://github.com/docker/compose/releases/download/1.26.2/docker-compose-Linux-x86_64
+ dest: /usr/local/bin/docker-compose
+ mode: 0755
+ - name: uninstall aws cli v1
+ file:
+ path: /bin/aws
+ state: absent
+ - name: Download awscliv2 installer
+ unarchive:
+ src: https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip
+ dest: /tmp
+ remote_src: yes
+ creates: /tmp/aws
+ mode: 0755
+ - name: Run the installer.
+ command:
+ args:
+ cmd: "/tmp/aws/install"
+ creates: /usr/local/bin/aws
+ - name: install ecr credential helper
+ yum:
+ name: amazon-ecr-credential-helper
+ state: present
+ - name: Create folder for config file of ecr cred helper
+ file:
+ path: /home/ec2-user/.docker
+ state: directory
+ owner: "ec2-user"
+ mode: "g+rwx"
+ - name: create config file with content for ecr creds
+ copy:
+ content: '{"credsStore":"ecr-login"}'
+ dest: /home/ec2-user/.docker/config.json
+ owner: "ec2-user"
+ mode: "g+rwx"
\ No newline at end of file
diff --git a/ansible/scripts/deploy_app_on_docker_swarm.sh b/ansible/scripts/deploy_app_on_docker_swarm.sh
new file mode 100644
index 0000000000..d36c706bfc
--- /dev/null
+++ b/ansible/scripts/deploy_app_on_docker_swarm.sh
@@ -0,0 +1,4 @@
+PATH="$PATH:/usr/local/bin"
+APP_NAME="petclinic"
+envsubst < docker-compose-swarm-dev.yml > docker-compose-swarm-dev-tagged.yml
+ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b --extra-vars "workspace=${WORKSPACE} app_name=${APP_NAME} aws_region=${AWS_REGION} ecr_registry=${ECR_REGISTRY}" ./ansible/playbooks/pb_deploy_app_on_docker_swarm.yaml
\ No newline at end of file
diff --git a/ansible/scripts/deploy_app_on_qa_environment.sh b/ansible/scripts/deploy_app_on_qa_environment.sh
new file mode 100644
index 0000000000..377b897fdb
--- /dev/null
+++ b/ansible/scripts/deploy_app_on_qa_environment.sh
@@ -0,0 +1,5 @@
+PATH="$PATH:/usr/local/bin"
+APP_NAME="petclinic"
+sed -i "s/APP_STACK_NAME/${APP_STACK_NAME}/" ./ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml
+envsubst < docker-compose-swarm-qa.yml > docker-compose-swarm-qa-tagged.yml
+ansible-playbook -i ./ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml -b --extra-vars "workspace=${WORKSPACE} app_name=${APP_NAME} aws_region=${AWS_REGION} ecr_registry=${ECR_REGISTRY}" ./ansible/playbooks/pb_deploy_app_on_qa_environment.yaml
\ No newline at end of file
diff --git a/ansible/scripts/run_dummy_selenium_job.sh b/ansible/scripts/run_dummy_selenium_job.sh
new file mode 100644
index 0000000000..4e5d10d053
--- /dev/null
+++ b/ansible/scripts/run_dummy_selenium_job.sh
@@ -0,0 +1,2 @@
+PATH="$PATH:/usr/local/bin"
+ansible-playbook --connection=local --inventory 127.0.0.1, --extra-vars "workspace=${WORKSPACE}" ./ansible/playbooks/pb_run_dummy_selenium_job.yaml
\ No newline at end of file
diff --git a/ansible/scripts/run_selenium_jobs.sh b/ansible/scripts/run_selenium_jobs.sh
new file mode 100644
index 0000000000..0306d867a0
--- /dev/null
+++ b/ansible/scripts/run_selenium_jobs.sh
@@ -0,0 +1,3 @@
+PATH="$PATH:/usr/local/bin"
+ansible-playbook -vvv --connection=local --inventory 127.0.0.1,
+--extra-vars "workspace=${WORKSPACE} master_public_ip=${GRAND_MASTER_PUBLIC_IP}" ./ansible/playbooks/pb_run_selenium_jobs.yaml
diff --git a/build-dev-docker-images.sh b/build-dev-docker-images.sh
new file mode 100644
index 0000000000..1c5441a219
--- /dev/null
+++ b/build-dev-docker-images.sh
@@ -0,0 +1,12 @@
+# build-dev-docker-images
+./mvnw clean package
+docker build --force-rm -t "petclinic-admin-server:dev" ./spring-petclinic-admin-server
+docker build --force-rm -t "petclinic-api-gateway:dev" ./spring-petclinic-api-gateway
+docker build --force-rm -t "petclinic-config-server:dev" ./spring-petclinic-config-server
+docker build --force-rm -t "petclinic-customers-service:dev" ./spring-petclinic-customers-service
+docker build --force-rm -t "petclinic-discovery-server:dev" ./spring-petclinic-discovery-server
+docker build --force-rm -t "petclinic-hystrix-dashboard:dev" ./spring-petclinic-hystrix-dashboard
+docker build --force-rm -t "petclinic-vets-service:dev" ./spring-petclinic-vets-service
+docker build --force-rm -t "petclinic-visits-service:dev" ./spring-petclinic-visits-service
+docker build --force-rm -t "petclinic-prometheus-server:dev" ./docker/prometheus
+docker build --force-rm -t "petclinic-grafana-server:dev" ./docker/grafana
\ No newline at end of file
diff --git a/docker-compose-local.yml b/docker-compose-local.yml
new file mode 100644
index 0000000000..195b20637c
--- /dev/null
+++ b/docker-compose-local.yml
@@ -0,0 +1,97 @@
+version: '2'
+services:
+ config-server:
+ image: petclinic-config-server:dev
+ container_name: config-server
+ mem_limit: 512M
+ ports:
+ - 8888:8888
+ discovery-server:
+ image: petclinic-discovery-server:dev
+ container_name: discovery-server
+ mem_limit: 512M
+ ports:
+ - 8761:8761
+ depends_on:
+ - config-server
+ entrypoint: ["./dockerize", "-wait=tcp://config-server:8888", "-timeout=60s", "--", "java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar" ]
+ customers-service:
+ image: petclinic-customers-service:dev
+ container_name: customers-service
+ mem_limit: 512M
+ ports:
+ - 8081:8081
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize", "-wait=tcp://discovery-server:8761", "-timeout=60s", "--", "java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar" ]
+ visits-service:
+ image: petclinic-visits-service:dev
+ container_name: visits-service
+ mem_limit: 512M
+ ports:
+ - 8082:8082
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize", "-wait=tcp://discovery-server:8761", "-timeout=60s", "--", "java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar" ]
+ vets-service:
+ image: petclinic-vets-service:dev
+ container_name: vets-service
+ mem_limit: 512M
+ ports:
+ - 8083:8083
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize", "-wait=tcp://discovery-server:8761", "-timeout=60s", "--", "java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar" ]
+ api-gateway:
+ image: petclinic-api-gateway:dev
+ container_name: api-gateway
+ mem_limit: 512M
+ ports:
+ - 8080:8080
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize", "-wait=tcp://discovery-server:8761", "-timeout=60s", "--", "java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar" ]
+ admin-server:
+ image: petclinic-admin-server:dev
+ container_name: admin-server
+ mem_limit: 512M
+ ports:
+ - 9090:9090
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize", "-wait=tcp://discovery-server:8761", "-timeout=60s", "--", "java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar" ]
+ hystrix-dashboard:
+ image: petclinic-hystrix-dashboard:dev
+ container_name: hystrix-dashboard
+ mem_limit: 512M
+ ports:
+ - 7979:7979
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize", "-wait=tcp://discovery-server:8761", "-timeout=60s", "--", "java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar" ]
+ tracing-server:
+ image: openzipkin/zipkin
+ container_name: tracing-server
+ mem_limit: 512M
+ environment:
+ - JAVA_OPTS=-XX:+UnlockExperimentalVMOptions -Djava.security.egd=file:/dev/./urandom
+ ports:
+ - 9411:9411
+ grafana-server:
+ image: petclinic-grafana-server:dev
+ container_name: grafana-server
+ mem_limit: 256M
+ ports:
+ - 3000:3000
+ prometheus-server:
+ image: petclinic-prometheus-server:dev
+ container_name: prometheus-server
+ mem_limit: 256M
+ ports:
+ - 9091:9090
\ No newline at end of file
diff --git a/docker-compose-swarm-dev.yml b/docker-compose-swarm-dev.yml
new file mode 100644
index 0000000000..4ccb0f2f25
--- /dev/null
+++ b/docker-compose-swarm-dev.yml
@@ -0,0 +1,125 @@
+version: '3.8'
+services:
+ config-server:
+ image: "${IMAGE_TAG_CONFIG_SERVER}"
+ networks:
+ - clarusnet
+ ports:
+ - 8888:8888
+ discovery-server:
+ image: "${IMAGE_TAG_DISCOVERY_SERVER}"
+ depends_on:
+ - config-server
+ entrypoint: ["./dockerize","-wait=tcp://config-server:8888","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8761:8761
+ customers-service:
+ image: "${IMAGE_TAG_CUSTOMERS_SERVICE}"
+ deploy:
+ replicas: 3
+ update_config:
+ parallelism: 2
+ delay: 5s
+ order: start-first
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8081:8081
+ visits-service:
+ image: "${IMAGE_TAG_VISITS_SERVICE}"
+ deploy:
+ replicas: 3
+ update_config:
+ parallelism: 2
+ delay: 5s
+ order: start-first
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8082:8082
+ vets-service:
+ image: "${IMAGE_TAG_VETS_SERVICE}"
+ deploy:
+ replicas: 3
+ update_config:
+ parallelism: 2
+ delay: 5s
+ order: start-first
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8083:8083
+ api-gateway:
+ image: "${IMAGE_TAG_API_GATEWAY}"
+ deploy:
+ replicas: 3
+ update_config:
+ parallelism: 2
+ delay: 5s
+ order: start-first
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8080:8080
+ tracing-server:
+ image: openzipkin/zipkin
+ environment:
+ - JAVA_OPTS=-XX:+UnlockExperimentalVMOptions -Djava.security.egd=file:/dev/./urandom
+ networks:
+ - clarusnet
+ ports:
+ - 9411:9411
+ admin-server:
+ image: "${IMAGE_TAG_ADMIN_SERVER}"
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 9090:9090
+ hystrix-dashboard:
+ image: "${IMAGE_TAG_HYSTRIX_DASHBOARD}"
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 7979:7979
+ ## Grafana / Prometheus
+ grafana-server:
+ image: "${IMAGE_TAG_GRAFANA_SERVICE}"
+ networks:
+ - clarusnet
+ ports:
+ - 3000:3000
+ prometheus-server:
+ image: "${IMAGE_TAG_PROMETHEUS_SERVICE}"
+ networks:
+ - clarusnet
+ ports:
+ - 9091:9090
+networks:
+ clarusnet:
+ driver: overlay
\ No newline at end of file
diff --git a/docker-compose-swarm-qa.yml b/docker-compose-swarm-qa.yml
new file mode 100644
index 0000000000..64211364a8
--- /dev/null
+++ b/docker-compose-swarm-qa.yml
@@ -0,0 +1,125 @@
+version: '3.8'
+services:
+ config-server:
+ image: "${IMAGE_TAG_CONFIG_SERVER}"
+ networks:
+ - clarusnet
+ ports:
+ - 8888:8888
+ discovery-server:
+ image: "${IMAGE_TAG_DISCOVERY_SERVER}"
+ depends_on:
+ - config-server
+ entrypoint: ["./dockerize","-wait=tcp://config-server:8888","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8761:8761
+ customers-service:
+ image: "${IMAGE_TAG_CUSTOMERS_SERVICE}"
+ deploy:
+ replicas: 3
+ update_config:
+ parallelism: 2
+ delay: 5s
+ order: start-first
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8081:8081
+ visits-service:
+ image: "${IMAGE_TAG_VISITS_SERVICE}"
+ deploy:
+ replicas: 3
+ update_config:
+ parallelism: 2
+ delay: 5s
+ order: start-first
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8082:8082
+ vets-service:
+ image: "${IMAGE_TAG_VETS_SERVICE}"
+ deploy:
+ replicas: 3
+ update_config:
+ parallelism: 2
+ delay: 5s
+ order: start-first
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8083:8083
+ api-gateway:
+ image: "${IMAGE_TAG_API_GATEWAY}"
+ deploy:
+ replicas: 5
+ update_config:
+ parallelism: 2
+ delay: 5s
+ order: start-first
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 8080:8080
+ tracing-server:
+ image: openzipkin/zipkin
+ environment:
+ - JAVA_OPTS=-XX:+UnlockExperimentalVMOptions -Djava.security.egd=file:/dev/./urandom
+ networks:
+ - clarusnet
+ ports:
+ - 9411:9411
+ admin-server:
+ image: "${IMAGE_TAG_ADMIN_SERVER}"
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 9090:9090
+ hystrix-dashboard:
+ image: "${IMAGE_TAG_HYSTRIX_DASHBOARD}"
+ depends_on:
+ - config-server
+ - discovery-server
+ entrypoint: ["./dockerize","-wait=tcp://discovery-server:8761","-timeout=60s","--","java", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
+ networks:
+ - clarusnet
+ ports:
+ - 7979:7979
+ ## Grafana / Prometheus
+ grafana-server:
+ image: "${IMAGE_TAG_GRAFANA_SERVICE}"
+ networks:
+ - clarusnet
+ ports:
+ - 3000:3000
+ prometheus-server:
+ image: "${IMAGE_TAG_PROMETHEUS_SERVICE}"
+ networks:
+ - clarusnet
+ ports:
+ - 9091:9090
+networks:
+ clarusnet:
+ driver: overlay
\ No newline at end of file
diff --git a/infrastructure/create-ecr-docker-registry-for-dev.sh b/infrastructure/create-ecr-docker-registry-for-dev.sh
new file mode 100644
index 0000000000..e9a729f251
--- /dev/null
+++ b/infrastructure/create-ecr-docker-registry-for-dev.sh
@@ -0,0 +1,8 @@
+PATH="$PATH:/usr/local/bin"
+APP_REPO_NAME="clarusway-repo/petclinic-app-dev"
+AWS_REGION="us-east-1"
+aws ecr create-repository \
+ --repository-name ${APP_REPO_NAME} \
+ --image-scanning-configuration scanOnPush=false \
+ --image-tag-mutability MUTABLE \
+ --region ${AWS_REGION}
\ No newline at end of file
diff --git a/infrastructure/create-qa-automation-environment.sh b/infrastructure/create-qa-automation-environment.sh
new file mode 100644
index 0000000000..8a2fa03d82
--- /dev/null
+++ b/infrastructure/create-qa-automation-environment.sh
@@ -0,0 +1,31 @@
+# Environment variables
+PATH="$PATH:/usr/local/bin"
+APP_NAME="Petclinic"
+CFN_KEYPAIR="Call-$APP_NAME-dev-${BUILD_NUMBER}.key"
+CFN_TEMPLATE="./infrastructure/dev-docker-swarm-infrastructure-cfn-template.yml"
+AWS_REGION="us-east-1"
+export ANSIBLE_PRIVATE_KEY_FILE="${WORKSPACE}/${CFN_KEYPAIR}"
+export ANSIBLE_HOST_KEY_CHECKING=False
+export APP_STACK_NAME="Call-$APP_NAME-App-${BUILD_NUMBER}"
+# Create key pair for Ansible
+aws ec2 create-key-pair --region ${AWS_REGION} --key-name ${CFN_KEYPAIR} --query "KeyMaterial" --output text > ${CFN_KEYPAIR}
+chmod 400 ${CFN_KEYPAIR}
+# Create infrastructure for Docker Swarm
+aws cloudformation create-stack --region ${AWS_REGION} --stack-name ${APP_STACK_NAME} --capabilities CAPABILITY_IAM --template-body file://${CFN_TEMPLATE} --parameters ParameterKey=KeyPairName,ParameterValue=${CFN_KEYPAIR}
+# Install Docker Swarm environment on the infrastructure
+# Update dynamic inventory (hosts/docker nodes)
+sed -i "s/APP_STACK_NAME/$APP_STACK_NAME/" ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml
+# Install common tools on all instances/nodes
+ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_setup_for_all_docker_swarm_instances.yaml
+# Initialize Docker Swarm on Grand Master
+ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_initialize_docker_swarm.yaml
+# Join the manager instances to the Swarm
+ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_join_docker_swarm_managers.yaml
+# Join the worker instances to the Swarm
+ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_join_docker_swarm_workers.yaml
+# Build, Deploy, Test the application
+# Tear down the Docker Swarm infrastructure
+aws cloudformation delete-stack --region ${AWS_REGION} --stack-name ${AWS_STACK_NAME}
+# Delete key pair
+aws ec2 delete-key-pair --region ${AWS_REGION} --key-name ${CFN_KEYPAIR}
+rm -rf ${CFN_KEYPAIR}
\ No newline at end of file
diff --git a/infrastructure/dev-docker-swarm-infrastructure-cfn-template.yml b/infrastructure/dev-docker-swarm-infrastructure-cfn-template.yml
new file mode 100644
index 0000000000..0302e30472
--- /dev/null
+++ b/infrastructure/dev-docker-swarm-infrastructure-cfn-template.yml
@@ -0,0 +1,179 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: >
+ This Cloudformation Template creates an infrastructure for Docker Swarm
+ with five EC2 Instances with Amazon Linux 2. Instances are configured
+ with custom security group allowing SSH (22), HTTP (80) UDP (4789, 7946),
+ and TCP(2377, 7946, 8080) connections from anywhere.
+ User needs to select appropriate key name when launching the template.
+Parameters:
+ KeyPairName:
+ Description: Enter the name of your Key Pair for SSH connections.
+ Type: AWS::EC2::KeyPair::KeyName
+ ConstraintDescription: Must one of the existing EC2 KeyPair
+Resources:
+ RoleEnablingEC2forECR:
+ Type: "AWS::IAM::Role"
+ Properties:
+ AssumeRolePolicyDocument:
+ Statement:
+ - Effect: Allow
+ Principal:
+ Service:
+ - ec2.amazonaws.com
+ Action:
+ - 'sts:AssumeRole'
+ ManagedPolicyArns:
+ - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
+ EC2Profile:
+ Type: "AWS::IAM::InstanceProfile"
+ Properties:
+ Roles: #required
+ - !Ref RoleEnablingEC2forECR
+ DockerMachinesSecurityGroup:
+ Type: AWS::EC2::SecurityGroup
+ Properties:
+ GroupDescription: Enable SSH and HTTP for Docker Machines
+ SecurityGroupIngress:
+ - IpProtocol: tcp
+ FromPort: 80
+ ToPort: 80
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 22
+ ToPort: 22
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 2377
+ ToPort: 2377
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 7946
+ ToPort: 7946
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: udp
+ FromPort: 7946
+ ToPort: 7946
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: udp
+ FromPort: 4789
+ ToPort: 4789
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8080
+ ToPort: 8080
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8088
+ ToPort: 8088
+ CidrIp: 0.0.0.0/0
+ DockerMachineLT:
+ Type: "AWS::EC2::LaunchTemplate"
+ Properties:
+ LaunchTemplateData:
+ ImageId: ami-0947d2ba12ee1ff75
+ InstanceType: t2.medium
+ KeyName: !Ref KeyPairName
+ IamInstanceProfile:
+ Arn: !GetAtt EC2Profile.Arn
+ SecurityGroupIds:
+ - !GetAtt DockerMachinesSecurityGroup.GroupId
+ TagSpecifications:
+ - ResourceType: instance
+ Tags:
+ - Key: app-stack-name
+ Value: !Sub ${AWS::StackName}
+ - Key: environment
+ Value: dev
+ DockerInstance1:
+ Type: AWS::EC2::Instance
+ DependsOn:
+ - "DockerInstance2"
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-1
+ - Key: swarm-role
+ Value: grand-master
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 1st
+ DockerInstance2:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-2
+ - Key: swarm-role
+ Value: manager
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 2nd
+ DockerInstance3:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-3
+ - Key: swarm-role
+ Value: manager
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 3rd
+ DockerInstance4:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-4
+ - Key: swarm-role
+ Value: worker
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 4th
+ DockerInstance5:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-5
+ - Key: swarm-role
+ Value: worker
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 5th
+Outputs:
+ 1stDockerInstanceDNSName:
+ Description: 1st Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance1.PublicDnsName
+ 2ndDockerInstanceDNSName:
+ Description: 2nd Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance2.PublicDnsName
+ 3rdDockerInstanceDNSName:
+ Description: 3rd Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance3.PublicDnsName
+ 4thDockerInstanceDNSName:
+ Description: 4th Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance4.PublicDnsName
+ 5thDockerInstanceDNSName:
+ Description: 5th Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance5.PublicDnsName
\ No newline at end of file
diff --git a/infrastructure/dev-server-for-petclinic-app-cfn-template.yml b/infrastructure/dev-server-for-petclinic-app-cfn-template.yml
new file mode 100644
index 0000000000..9e3e93e251
--- /dev/null
+++ b/infrastructure/dev-server-for-petclinic-app-cfn-template.yml
@@ -0,0 +1,118 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: >
+ This Cloudformation template prepares development environment for
+ Petclinic Microservices Application.
+ User needs to select appropriate key name when launching the template.
+Parameters:
+ KeyPairName:
+ Description: Enter the name of your Key Pair for SSH connections.
+ Type: AWS::EC2::KeyPair::KeyName
+ ConstraintDescription: Must one of the existing EC2 KeyPair
+Resources:
+ PetclinicDemoSG:
+ Type: AWS::EC2::SecurityGroup
+ Properties:
+ GroupDescription: Enable SSH and HTTP for Petclinic Microservices
+ SecurityGroupIngress:
+ - IpProtocol: tcp
+ FromPort: 80
+ ToPort: 80
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 22
+ ToPort: 22
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 9090
+ ToPort: 9090
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8080
+ ToPort: 8080
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8081
+ ToPort: 8081
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8082
+ ToPort: 8082
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8083
+ ToPort: 8083
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8888
+ ToPort: 8888
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 9411
+ ToPort: 9411
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 7979
+ ToPort: 7979
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 3000
+ ToPort: 3000
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 9091
+ ToPort: 9091
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8761
+ ToPort: 8761
+ CidrIp: 0.0.0.0/0
+ PetclinicServerLT:
+ Type: "AWS::EC2::LaunchTemplate"
+ Properties:
+ LaunchTemplateData:
+ ImageId: ami-0947d2ba12ee1ff75
+ InstanceType: t2.medium
+ KeyName: !Ref KeyPairName
+ SecurityGroupIds:
+ - !GetAtt PetclinicDemoSG.GroupId
+ UserData:
+ Fn::Base64: |
+
+ #! /bin/bash
+ # update os
+ yum update -y
+ # set hostname as petclinic-dev-server
+ hostnamectl set-hostname petclinic-dev-server
+ # install docker
+ amazon-linux-extras install docker -y
+ systemctl start docker
+ systemctl enable docker
+ usermod -a -G docker ec2-user
+ # install docker compose
+ curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
+ chmod +x /usr/local/bin/docker-compose
+ # install JDK 11
+ yum install java-11-amazon-corretto -y
+ # install Git
+ yum install git -y
+ cd /home/ec2-user
+ git clone https://github.com/huseyin-yigit/microservices-ci-cd-pipeline-with-petclinic-app.git
+ git fetch
+ git checkout dev
+
+
+
+
+ PetclinicServer:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref PetclinicServerLT
+ Version: !GetAtt PetclinicServerLT.LatestVersionNumber
+ Tags:
+ - Key: Name
+ Value: !Sub Petclinic App Dev Server of ${AWS::StackName}
+Outputs:
+ PetclinicServerDNSName:
+ Description: Petclinic App URL
+ Value: !GetAtt PetclinicServer.PublicDnsName
\ No newline at end of file
diff --git a/infrastructure/docker-swarm-infrastructure-cfn-template.yml b/infrastructure/docker-swarm-infrastructure-cfn-template.yml
new file mode 100644
index 0000000000..091aa3ccc9
--- /dev/null
+++ b/infrastructure/docker-swarm-infrastructure-cfn-template.yml
@@ -0,0 +1,173 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: |
+ This Cloudformation Template creates an infrastructure for Docker Swarm
+ with five EC2 Instances with Amazon Linux 2. Instances are configured
+ with custom security group allowing SSH (22), HTTP (80) UDP (4789, 7946),
+ and TCP(2377, 7946, 8080) connections from anywhere.
+ User needs to select appropriate key name when launching the template.
+Parameters:
+ KeyPairName:
+ Description: Enter the name of your Key Pair for SSH connections.
+ Type: AWS::EC2::KeyPair::KeyName
+ ConstraintDescription: Must one of the existing EC2 KeyPair
+Resources:
+ RoleEnablingEC2forECR:
+ Type: "AWS::IAM::Role"
+ Properties:
+ AssumeRolePolicyDocument:
+ Statement:
+ - Effect: Allow
+ Principal:
+ Service:
+ - ec2.amazonaws.com
+ Action:
+ - 'sts:AssumeRole'
+ ManagedPolicyArns:
+ - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
+ EC2Profile:
+ Type: "AWS::IAM::InstanceProfile"
+ Properties:
+ Roles: #required
+ - !Ref RoleEnablingEC2forECR
+ DockerMachinesSecurityGroup:
+ Type: AWS::EC2::SecurityGroup
+ Properties:
+ GroupDescription: Enable SSH and HTTP for Docker Machines
+ SecurityGroupIngress:
+ - IpProtocol: tcp
+ FromPort: 80
+ ToPort: 80
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 22
+ ToPort: 22
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 2377
+ ToPort: 2377
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 7946
+ ToPort: 7946
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: udp
+ FromPort: 7946
+ ToPort: 7946
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: udp
+ FromPort: 4789
+ ToPort: 4789
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8080
+ ToPort: 8080
+ CidrIp: 0.0.0.0/0
+ DockerMachineLT:
+ Type: "AWS::EC2::LaunchTemplate"
+ Properties:
+ LaunchTemplateData:
+ ImageId: ami-0947d2ba12ee1ff75
+ InstanceType: t2.micro
+ KeyName: !Ref KeyPairName
+ IamInstanceProfile:
+ Arn: !GetAtt EC2Profile.Arn
+ SecurityGroupIds:
+ - !GetAtt DockerMachinesSecurityGroup.GroupId
+ TagSpecifications:
+ - ResourceType: instance
+ Tags:
+ - Key: app-stack-name
+ Value: !Sub ${AWS::StackName}
+ - Key: environment
+ Value: dev
+ DockerInstance1:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-1
+ - Key: swarm-role
+ Value: grand-master
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 1st
+ DockerInstance2:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-2
+ - Key: swarm-role
+ Value: manager
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 2nd
+ DockerInstance3:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-3
+ - Key: swarm-role
+ Value: manager
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 3rd
+ DockerInstance4:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-4
+ - Key: swarm-role
+ Value: worker
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 4th
+ DockerInstance5:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-5
+ - Key: swarm-role
+ Value: worker
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 5th
+Outputs:
+ 1stDockerInstanceDNSName:
+ Description: 1st Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance1.PublicDnsName
+ 2ndDockerInstanceDNSName:
+ Description: 2nd Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance2.PublicDnsName
+ 3rdDockerInstanceDNSName:
+ Description: 3rd Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance3.PublicDnsName
+ 4thDockerInstanceDNSName:
+ Description: 4th Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance4.PublicDnsName
+ 5thDockerInstanceDNSName:
+ Description: 5th Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance5.PublicDnsName
\ No newline at end of file
diff --git a/infrastructure/jenkins-server-cfn-template.yml b/infrastructure/jenkins-server-cfn-template.yml
new file mode 100644
index 0000000000..4beea17421
--- /dev/null
+++ b/infrastructure/jenkins-server-cfn-template.yml
@@ -0,0 +1,153 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: >
+ This Cloudformation Template creates a Jenkins Server using JDK 11 on EC2 Instance.
+ Jenkins Server is enabled with Git, Docker and Docker Compose,
+ AWS CLI Version 2, ECR Credential Helper, Python 3, Ansible, and Boto3.
+ Jenkins Server will run on Amazon Linux 2 EC2 Instance with
+ custom security group allowing HTTP(80, 8080) and SSH (22) connections from anywhere.
+Parameters:
+ KeyPairName:
+ Description: Enter the name of your Key Pair for SSH connections.
+ Type: AWS::EC2::KeyPair::KeyName
+ ConstraintDescription: Must one of the existing EC2 KeyPair
+Resources:
+ EmpoweringPolicyforJenkinsServer:
+ Type: "AWS::IAM::ManagedPolicy"
+ Properties:
+ PolicyDocument: #required
+ Version: 2012-10-17
+ Statement:
+ - Effect: Allow
+ Action:
+ - iam:AddRoleToInstanceProfile
+ - iam:CreateInstanceProfile
+ - iam:CreatePolicy
+ - iam:CreateRole
+ - iam:DeleteInstanceProfile
+ - iam:DeletePolicy
+ - iam:DeleteRole
+ - iam:GetPolicy
+ - iam:GetRole
+ - iam:ListPolicyVersions
+ - iam:AttachRolePolicy
+ - iam:DetachRolePolicy
+ - iam:PassRole
+ - iam:RemoveRoleFromInstanceProfile
+ - iam:GetInstanceProfile
+ Resource: "*"
+ - Effect: Allow
+ Action:
+ - ec2:*
+ Resource: "*"
+ EmpoweringRoleforJenkinsServer:
+ Type: "AWS::IAM::Role"
+ Properties:
+ AssumeRolePolicyDocument:
+ Statement:
+ - Effect: Allow
+ Principal:
+ Service:
+ - ec2.amazonaws.com
+ Action:
+ - 'sts:AssumeRole'
+ ManagedPolicyArns:
+ - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
+ - arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
+ - !Ref EmpoweringPolicyforJenkinsServer
+ JenkinsServerEC2Profile:
+ Type: "AWS::IAM::InstanceProfile"
+ Properties:
+ Roles: #required
+ - !Ref EmpoweringRoleforJenkinsServer
+ JenkinsServerSecurityGroup:
+ Type: AWS::EC2::SecurityGroup
+ Properties:
+ GroupDescription: Enable SSH and HTTP for Jenkins Server
+ SecurityGroupIngress:
+ - IpProtocol: tcp
+ FromPort: 80
+ ToPort: 80
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8080
+ ToPort: 8080
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 22
+ ToPort: 22
+ CidrIp: 0.0.0.0/0
+ JenkinsServer:
+ Type: AWS::EC2::Instance
+ Properties:
+ ImageId: ami-0947d2ba12ee1ff75
+ InstanceType: t2.medium
+ KeyName: !Ref KeyPairName
+ IamInstanceProfile: !Ref JenkinsServerEC2Profile
+ SecurityGroupIds:
+ - !GetAtt JenkinsServerSecurityGroup.GroupId
+ Tags:
+ - Key: Name
+ Value: !Sub Jenkins Server of ${AWS::StackName}
+ - Key: server
+ Value: jenkins
+ UserData:
+ Fn::Base64: |
+ #! /bin/bash
+ # update os
+ yum update -y
+ # set server hostname as jenkins-server
+ hostnamectl set-hostname jenkins-server
+ # install git
+ yum install git -y
+ # install java 11
+ yum install java-11-amazon-corretto -y
+ # install jenkins
+ wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo
+ rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
+ yum install jenkins -y
+ systemctl start jenkins
+ systemctl enable jenkins
+ # install docker
+ amazon-linux-extras install docker -y
+ systemctl start docker
+ systemctl enable docker
+ usermod -a -G docker ec2-user
+ usermod -a -G docker jenkins
+ # configure docker as cloud agent for jenkins
+ cp /lib/systemd/system/docker.service /lib/systemd/system/docker.service.bak
+ sed -i 's/^ExecStart=.*/ExecStart=\/usr\/bin\/dockerd -H tcp:\/\/127.0.0.1:2375 -H unix:\/\/\/var\/run\/docker.sock/g' /lib/systemd/system/docker.service
+ systemctl daemon-reload
+ systemctl restart docker
+ systemctl restart jenkins
+ # install docker compose
+ curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" \
+ -o /usr/local/bin/docker-compose
+ chmod +x /usr/local/bin/docker-compose
+ # uninstall aws cli version 1
+ rm -rf /bin/aws
+ # install aws cli version 2
+ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
+ unzip awscliv2.zip
+ ./aws/install
+ # install aws ecr credential helper
+ yum install amazon-ecr-credential-helper -y
+ mkdir -p /home/jenkins/.docker
+ cd /home/jenkins/.docker
+ echo '{"credsStore": "ecr-login"}' > config.json
+ # install python 3
+ yum install python3 -y
+ # install ansible
+ pip3 install ansible
+ # install boto3
+ pip3 install boto3
+Outputs:
+ JenkinsDNS:
+ Description: Jenkins Server DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt JenkinsServer.PublicDnsName
+ JenkinsURL:
+ Description: Jenkins Server URL
+ Value: !Sub
+ - http://${PublicAddress}:8080
+ - PublicAddress: !GetAtt JenkinsServer.PublicDnsName
\ No newline at end of file
diff --git a/infrastructure/qa-docker-swarm-infrastructure-cfn-template.yml b/infrastructure/qa-docker-swarm-infrastructure-cfn-template.yml
new file mode 100644
index 0000000000..602e2e1ceb
--- /dev/null
+++ b/infrastructure/qa-docker-swarm-infrastructure-cfn-template.yml
@@ -0,0 +1,179 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: >
+ This Cloudformation Template creates an infrastructure for Docker Swarm
+ with five EC2 Instances with Amazon Linux 2. Instances are configured
+ with custom security group allowing SSH (22), HTTP (80) UDP (4789, 7946),
+ and TCP(2377, 7946, 8080) connections from anywhere.
+ User needs to select appropriate key name when launching the template.
+Parameters:
+ KeyPairName:
+ Description: Enter the name of your Key Pair for SSH connections.
+ Type: AWS::EC2::KeyPair::KeyName
+ ConstraintDescription: Must one of the existing EC2 KeyPair
+Resources:
+ RoleEnablingEC2forECR:
+ Type: "AWS::IAM::Role"
+ Properties:
+ AssumeRolePolicyDocument:
+ Statement:
+ - Effect: Allow
+ Principal:
+ Service:
+ - ec2.amazonaws.com
+ Action:
+ - 'sts:AssumeRole'
+ ManagedPolicyArns:
+ - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
+ EC2Profile:
+ Type: "AWS::IAM::InstanceProfile"
+ Properties:
+ Roles: #required
+ - !Ref RoleEnablingEC2forECR
+ DockerMachinesSecurityGroup:
+ Type: AWS::EC2::SecurityGroup
+ Properties:
+ GroupDescription: Enable SSH and HTTP for Docker Machines
+ SecurityGroupIngress:
+ - IpProtocol: tcp
+ FromPort: 80
+ ToPort: 80
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 22
+ ToPort: 22
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 2377
+ ToPort: 2377
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 7946
+ ToPort: 7946
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: udp
+ FromPort: 7946
+ ToPort: 7946
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: udp
+ FromPort: 4789
+ ToPort: 4789
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8080
+ ToPort: 8080
+ CidrIp: 0.0.0.0/0
+ - IpProtocol: tcp
+ FromPort: 8088
+ ToPort: 8088
+ CidrIp: 0.0.0.0/0
+ DockerMachineLT:
+ Type: "AWS::EC2::LaunchTemplate"
+ Properties:
+ LaunchTemplateData:
+ ImageId: ami-0947d2ba12ee1ff75
+ InstanceType: t2.medium
+ KeyName: !Ref KeyPairName
+ IamInstanceProfile:
+ Arn: !GetAtt EC2Profile.Arn
+ SecurityGroupIds:
+ - !GetAtt DockerMachinesSecurityGroup.GroupId
+ TagSpecifications:
+ - ResourceType: instance
+ Tags:
+ - Key: app-stack-name
+ Value: !Sub ${AWS::StackName}
+ - Key: environment
+ Value: qa
+ DockerInstance1:
+ Type: AWS::EC2::Instance
+ DependsOn:
+ - "DockerInstance2"
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-1
+ - Key: swarm-role
+ Value: grand-master
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 1st
+ DockerInstance2:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-2
+ - Key: swarm-role
+ Value: manager
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 2nd
+ DockerInstance3:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-3
+ - Key: swarm-role
+ Value: manager
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 3rd
+ DockerInstance4:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-4
+ - Key: swarm-role
+ Value: worker
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 4th
+ DockerInstance5:
+ Type: AWS::EC2::Instance
+ Properties:
+ LaunchTemplate:
+ LaunchTemplateId: !Ref DockerMachineLT
+ Version: !GetAtt DockerMachineLT.LatestVersionNumber
+ Tags:
+ - Key: server
+ Value: docker-instance-5
+ - Key: swarm-role
+ Value: worker
+ - Key: Name
+ Value: !Sub ${AWS::StackName} Docker Machine 5th
+Outputs:
+ 1stDockerInstanceDNSName:
+ Description: 1st Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance1.PublicDnsName
+ 2ndDockerInstanceDNSName:
+ Description: 2nd Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance2.PublicDnsName
+ 3rdDockerInstanceDNSName:
+ Description: 3rd Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance3.PublicDnsName
+ 4thDockerInstanceDNSName:
+ Description: 4th Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance4.PublicDnsName
+ 5thDockerInstanceDNSName:
+ Description: 5th Docker Instance DNS Name
+ Value: !Sub
+ - ${PublicAddress}
+ - PublicAddress: !GetAtt DockerInstance5.PublicDnsName
\ No newline at end of file
diff --git a/jenkins/build-and-deploy-petclinic-on-qa-env-manually.sh b/jenkins/build-and-deploy-petclinic-on-qa-env-manually.sh
new file mode 100644
index 0000000000..db30b11526
--- /dev/null
+++ b/jenkins/build-and-deploy-petclinic-on-qa-env-manually.sh
@@ -0,0 +1,22 @@
+PATH="$PATH:/usr/local/bin"
+APP_NAME="petclinic"
+APP_REPO_NAME="huseyin-repo/petclinic-app-qa"
+APP_STACK_NAME="Huseyin-petclinic-App-QA-1"
+CFN_KEYPAIR="huseyin-petclinic-qa.key"
+AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
+AWS_REGION="us-east-1"
+ECR_REGISTRY="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
+export ANSIBLE_PRIVATE_KEY_FILE="${JENKINS_HOME}/.ssh/${CFN_KEYPAIR}"
+export ANSIBLE_HOST_KEY_CHECKING="False"
+echo 'Packaging the App into Jars with Maven'
+. ./jenkins/package-with-maven-container.sh
+echo 'Preparing QA Tags for Docker Images'
+. ./jenkins/prepare-tags-ecr-for-qa-docker-images.sh
+echo 'Building App QA Images'
+. ./jenkins/build-qa-docker-images-for-ecr.sh
+echo "Pushing App QA Images to ECR Repo"
+. ./jenkins/push-qa-docker-images-to-ecr.sh
+echo 'Deploying App on Swarm'
+. ./ansible/scripts/deploy_app_on_qa_environment.sh
+echo 'Deleting all local images'
+docker image prune -af
\ No newline at end of file
diff --git a/jenkins/build-dev-docker-images-for-ecr.sh b/jenkins/build-dev-docker-images-for-ecr.sh
new file mode 100644
index 0000000000..4ea98df327
--- /dev/null
+++ b/jenkins/build-dev-docker-images-for-ecr.sh
@@ -0,0 +1,10 @@
+docker build --force-rm -t "${IMAGE_TAG_ADMIN_SERVER}" "${WORKSPACE}/spring-petclinic-admin-server"
+docker build --force-rm -t "${IMAGE_TAG_API_GATEWAY}" "${WORKSPACE}/spring-petclinic-api-gateway"
+docker build --force-rm -t "${IMAGE_TAG_CONFIG_SERVER}" "${WORKSPACE}/spring-petclinic-config-server"
+docker build --force-rm -t "${IMAGE_TAG_CUSTOMERS_SERVICE}" "${WORKSPACE}/spring-petclinic-customers-service"
+docker build --force-rm -t "${IMAGE_TAG_DISCOVERY_SERVER}" "${WORKSPACE}/spring-petclinic-discovery-server"
+docker build --force-rm -t "${IMAGE_TAG_HYSTRIX_DASHBOARD}" "${WORKSPACE}/spring-petclinic-hystrix-dashboard"
+docker build --force-rm -t "${IMAGE_TAG_VETS_SERVICE}" "${WORKSPACE}/spring-petclinic-vets-service"
+docker build --force-rm -t "${IMAGE_TAG_VISITS_SERVICE}" "${WORKSPACE}/spring-petclinic-visits-service"
+docker build --force-rm -t "${IMAGE_TAG_GRAFANA_SERVICE}" "${WORKSPACE}/docker/grafana"
+docker build --force-rm -t "${IMAGE_TAG_PROMETHEUS_SERVICE}" "${WORKSPACE}/docker/prometheus"
\ No newline at end of file
diff --git a/jenkins/build-qa-docker-images-for-ecr.sh b/jenkins/build-qa-docker-images-for-ecr.sh
new file mode 100644
index 0000000000..7ae5bfdfde
--- /dev/null
+++ b/jenkins/build-qa-docker-images-for-ecr.sh
@@ -0,0 +1,11 @@
+aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ECR_REGISTRY}
+docker push "${IMAGE_TAG_ADMIN_SERVER}"
+docker push "${IMAGE_TAG_API_GATEWAY}"
+docker push "${IMAGE_TAG_CONFIG_SERVER}"
+docker push "${IMAGE_TAG_CUSTOMERS_SERVICE}"
+docker push "${IMAGE_TAG_DISCOVERY_SERVER}"
+docker push "${IMAGE_TAG_HYSTRIX_DASHBOARD}"
+docker push "${IMAGE_TAG_VETS_SERVICE}"
+docker push "${IMAGE_TAG_VISITS_SERVICE}"
+docker push "${IMAGE_TAG_GRAFANA_SERVICE}"
+docker push "${IMAGE_TAG_PROMETHEUS_SERVICE}"
\ No newline at end of file
diff --git a/jenkins/create-permanent-key-pair-for-qa-environment.sh b/jenkins/create-permanent-key-pair-for-qa-environment.sh
new file mode 100644
index 0000000000..3b6013abf1
--- /dev/null
+++ b/jenkins/create-permanent-key-pair-for-qa-environment.sh
@@ -0,0 +1,8 @@
+PATH="$PATH:/usr/local/bin"
+APP_NAME="petclinic"
+CFN_KEYPAIR="huseyin-${APP_NAME}-qa.key"
+AWS_REGION="us-east-1"
+aws ec2 create-key-pair --region ${AWS_REGION} --key-name ${CFN_KEYPAIR} --query "KeyMaterial" --output text > ${CFN_KEYPAIR}
+chmod 400 ${CFN_KEYPAIR}
+cp ${CFN_KEYPAIR} ${JENKINS_HOME}/.ssh/${CFN_KEYPAIR}
+ls -al ${JENKINS_HOME}/.ssh
\ No newline at end of file
diff --git a/jenkins/jenkins-petclinic-ci-job.sh b/jenkins/jenkins-petclinic-ci-job.sh
new file mode 100644
index 0000000000..66e6e22f18
--- /dev/null
+++ b/jenkins/jenkins-petclinic-ci-job.sh
@@ -0,0 +1,2 @@
+echo 'Running Unit Tests on Petclinic Application'
+docker run --rm -v $HOME/.m2:/root/.m2 -v `pwd`:/app -w /app maven:3.6.3-openjdk-11 mvn clean test
\ No newline at end of file
diff --git a/jenkins/jenkinsfile-create-qa-environment-on-docker-swarm b/jenkins/jenkinsfile-create-qa-environment-on-docker-swarm
new file mode 100644
index 0000000000..f198e46c38
--- /dev/null
+++ b/jenkins/jenkinsfile-create-qa-environment-on-docker-swarm
@@ -0,0 +1,65 @@
+pipeline {
+ agent { label "master" }
+ environment {
+ PATH=sh(script:"echo $PATH:/usr/local/bin", returnStdout:true).trim()
+ APP_NAME="petclinic"
+ APP_STACK_NAME="Huseyin-$APP_NAME-App-QA-${BUILD_NUMBER}"
+ AWS_REGION="us-east-1"
+ CFN_KEYPAIR="huseyin-${APP_NAME}-qa.key"
+ CFN_TEMPLATE="./infrastructure/qa-docker-swarm-infrastructure-cfn-template.yml"
+ ANSIBLE_PRIVATE_KEY_FILE="${JENKINS_HOME}/.ssh/${CFN_KEYPAIR}"
+ ANSIBLE_HOST_KEY_CHECKING="False"
+ }
+ stages {
+ stage('Create QA Environment Infrastructure') {
+ steps {
+ echo 'Creating Infrastructure for QA Environment with Cloudfomation'
+ sh "aws cloudformation create-stack --region ${AWS_REGION} --stack-name ${APP_STACK_NAME} --capabilities CAPABILITY_IAM --template-body file://${CFN_TEMPLATE} --parameters ParameterKey=KeyPairName,ParameterValue=${CFN_KEYPAIR}"
+ script {
+ while(true) {
+ echo "Docker Grand Master is not UP and running yet. Will try to reach again after 10 seconds..."
+ sleep(10)
+ ip = sh(script:"aws ec2 describe-instances --region ${AWS_REGION} --filters Name=tag-value,Values=grand-master Name=tag-value,Values=${APP_STACK_NAME} --query Reservations[*].Instances[*].[PublicIpAddress] --output text", returnStdout:true).trim()
+ if (ip.length() >= 7) {
+ echo "Docker Grand Master Public Ip Address Found: $ip"
+ env.GRAND_MASTER_PUBLIC_IP = "$ip"
+ break
+ }
+ }
+ while(true) {
+ try{
+ sh "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${JENKINS_HOME}/.ssh/${CFN_KEYPAIR} ec2-user@${GRAND_MASTER_PUBLIC_IP} hostname"
+ echo "Docker Grand Master is reachable with SSH."
+ break
+ }
+ catch(Exception){
+ echo "Could not connect to Docker Grand Master with SSH, I will try again in 10 seconds"
+ sleep(10)
+ }
+ }
+ }
+ }
+ }
+ stage('Create Docker Swarm for QA Environment') {
+ steps {
+ echo "Setup Docker Swarm for QA Environment for ${APP_NAME} App"
+ echo "Update dynamic environment"
+ sh "sed -i 's/APP_STACK_NAME/${APP_STACK_NAME}/' ./ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml"
+ echo "Swarm Setup for all nodes (instances)"
+ sh "ansible-playbook -i ./ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_setup_for_all_docker_swarm_instances.yaml"
+ echo "Swarm Setup for Grand Master node"
+ sh "ansible-playbook -i ./ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_initialize_docker_swarm.yaml"
+ echo "Swarm Setup for Other Managers nodes"
+ sh "ansible-playbook -i ./ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_join_docker_swarm_managers.yaml"
+ echo "Swarm Setup for Workers nodes"
+ sh "ansible-playbook -i ./ansible/inventory/qa_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_join_docker_swarm_workers.yaml"
+ }
+ }
+ }
+ post {
+ failure {
+ echo 'Tear down the Docker Swarm infrastructure using AWS CLI'
+ sh "aws cloudformation delete-stack --region ${AWS_REGION} --stack-name ${APP_STACK_NAME}"
+ }
+ }
+}
\ No newline at end of file
diff --git a/jenkins/jenkinsfile-petclinic-nightly b/jenkins/jenkinsfile-petclinic-nightly
new file mode 100644
index 0000000000..f99776a6e0
--- /dev/null
+++ b/jenkins/jenkinsfile-petclinic-nightly
@@ -0,0 +1,179 @@
+pipeline {
+ agent { label "master" }
+ environment {
+ PATH=sh(script:"echo $PATH:/usr/local/bin", returnStdout:true).trim()
+ APP_NAME="petclinic"
+ APP_STACK_NAME="Huseyin-${APP_NAME}-app-dev-${BUILD_NUMBER}"
+ APP_REPO_NAME="huseyin-repo/${APP_NAME}-app-dev"
+ AWS_ACCOUNT_ID=sh(script:'export PATH="$PATH:/usr/local/bin" && aws sts get-caller-identity --query Account --output text', returnStdout:true).trim()
+ AWS_REGION="us-east-1"
+ ECR_REGISTRY="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
+ CFN_KEYPAIR="huseyin-${APP_NAME}-dev-${BUILD_NUMBER}.key"
+ CFN_TEMPLATE="./infrastructure/dev-docker-swarm-infrastructure-cfn-template.yml"
+ ANSIBLE_PRIVATE_KEY_FILE="${WORKSPACE}/${CFN_KEYPAIR}"
+ ANSIBLE_HOST_KEY_CHECKING="False"
+ }
+ stages {
+ stage('Create ECR Repo'){
+ steps {
+ echo "Creating ECR Repo for ${APP_NAME} app"
+ sh """
+ aws ecr create-repository \
+ --repository-name ${APP_REPO_NAME} \
+ --image-scanning-configuration scanOnPush=false \
+ --image-tag-mutability MUTABLE \
+ --region ${AWS_REGION}
+ """
+ }
+ }
+ stage('Package Application'){
+ steps {
+ echo 'Packaging the app into jars with maven'
+ sh ". ./jenkins/package-with-maven-container.sh"
+ }
+ }
+ stage('Prepare Tags for Docker Images'){
+ steps {
+ echo 'Preparing Tags for Docker Images'
+ script {
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-admin-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_ADMIN_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:admin-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-api-gateway/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_API_GATEWAY="${ECR_REGISTRY}/${APP_REPO_NAME}:api-gateway-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-config-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_CONFIG_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:config-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-customers-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_CUSTOMERS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:customers-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-discovery-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_DISCOVERY_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:discovery-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-hystrix-dashboard/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_HYSTRIX_DASHBOARD="${ECR_REGISTRY}/${APP_REPO_NAME}:hystrix-dashboard-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-vets-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_VETS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:vets-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-visits-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_VISITS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:visits-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ env.IMAGE_TAG_GRAFANA_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:grafana-service"
+ env.IMAGE_TAG_PROMETHEUS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:prometheus-service"
+ }
+ }
+ }
+ stage('Build App Docker Images'){
+ steps {
+ echo 'Building App Dev Images'
+ sh ". ./jenkins/build-dev-docker-images-for-ecr.sh"
+ sh 'docker image ls'
+ }
+ }
+ stage('Push Images to ECR Repo'){
+ steps {
+ echo "Pushing ${APP_NAME} App Images to ECR Repo"
+ sh ". ./jenkins/push-dev-docker-images-to-ecr.sh"
+ }
+ }
+ stage('Create Key Pair for Ansible'){
+ steps {
+ echo "Creating Key Pair for ${APP_NAME} App"
+ sh "aws ec2 create-key-pair --region ${AWS_REGION} --key-name ${CFN_KEYPAIR} --query KeyMaterial --output text > ${CFN_KEYPAIR}"
+ sh "chmod 400 ${CFN_KEYPAIR}"
+ }
+ }
+ stage('Create QA Automation Infrastructure') {
+ steps {
+ echo 'Creating QA Automation Infrastructure for Dev Environment with Cloudfomation'
+ sh "aws cloudformation create-stack --region ${AWS_REGION} --stack-name ${APP_STACK_NAME} --capabilities CAPABILITY_IAM --template-body file://${CFN_TEMPLATE} --parameters ParameterKey=KeyPairName,ParameterValue=${CFN_KEYPAIR}"
+
+ script {
+ while(true) {
+ echo "Docker Grand Master is not UP and running yet. Will try to reach again after 10 seconds..."
+ sleep(10)
+
+ ip = sh(script:"aws ec2 describe-instances --region ${AWS_REGION} --filters Name=tag-value,Values=grand-master Name=tag-value,Values=${APP_STACK_NAME} --query Reservations[*].Instances[*].[PublicIpAddress] --output text", returnStdout:true).trim()
+
+ if (ip.length() >= 7) {
+ echo "Docker Grand Master Public Ip Address Found: $ip"
+ env.GRAND_MASTER_PUBLIC_IP = "$ip"
+ break
+ }
+ }
+ while(true) {
+ try{
+ sh "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${WORKSPACE}/${CFN_KEYPAIR} ec2-user@${GRAND_MASTER_PUBLIC_IP} hostname"
+ echo "Docker Grand Master is reachable with SSH."
+ break
+ }
+ catch(Exception){
+ echo "Could not connect to Docker Grand Master with SSH, I will try again in 10 seconds"
+ sleep(10)
+ }
+ }
+ }
+ }
+ }
+ stage('Create Docker Swarm for QA Automation Build'){
+ steps {
+ echo "Setup Docker Swarm for QA Automation Build for ${APP_NAME} App"
+ echo "Update dynamic environment"
+ sh "sed -i 's/APP_STACK_NAME/${APP_STACK_NAME}/' ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml"
+ echo "Swarm Setup for all nodes (instances)"
+ sh "ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_setup_for_all_docker_swarm_instances.yaml"
+ echo "Swarm Setup for Grand Master node"
+ sh "ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_initialize_docker_swarm.yaml"
+ echo "Swarm Setup for Other Managers nodes"
+ sh "ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_join_docker_swarm_managers.yaml"
+ echo "Swarm Setup for Workers nodes"
+ sh "ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b ./ansible/playbooks/pb_join_docker_swarm_workers.yaml"
+ }
+ }
+ stage('Deploy App on Docker Swarm'){
+ steps {
+ echo 'Deploying App on Swarm'
+ sh 'envsubst < docker-compose-swarm-dev.yml > docker-compose-swarm-dev-tagged.yml'
+ sh 'ansible-playbook -i ./ansible/inventory/dev_stack_dynamic_inventory_aws_ec2.yaml -b --extra-vars "workspace=${WORKSPACE} app_name=${APP_NAME} aws_region=${AWS_REGION} ecr_registry=${ECR_REGISTRY}" ./ansible/playbooks/pb_deploy_app_on_docker_swarm.yaml'
+ }
+ }
+ stage('Test the Application Deployment'){
+ steps {
+ echo "Check if the ${APP_NAME} app is ready or not"
+ script {
+ while(true) {
+ try{
+ sh "curl -s ${GRAND_MASTER_PUBLIC_IP}:8080"
+ echo "${APP_NAME} app is successfully deployed."
+ break
+ }
+ catch(Exception){
+ echo "Could not connect to ${APP_NAME} app"
+ sleep(5)
+ }
+ }
+ }
+ }
+
+ }
+ stage('Run QA Automation Tests'){
+ steps {
+ echo "Run the Selenium Functional Test on QA Environment"
+ sh 'ansible-playbook -vvv --connection=local --inventory 127.0.0.1, --extra-vars "workspace=${WORKSPACE} master_public_ip=${GRAND_MASTER_PUBLIC_IP}" ./ansible/playbooks/pb_run_selenium_jobs.yaml'
+ }
+ }
+ }
+ post {
+ always {
+ echo 'Deleting all local images'
+ sh 'docker image prune -af'
+ echo 'Delete the Image Repository on ECR'
+ sh """
+ aws ecr delete-repository \
+ --repository-name ${APP_REPO_NAME} \
+ --region ${AWS_REGION}\
+ --force
+ """
+ echo 'Tear down the Docker Swarm infrastructure using AWS CLI'
+ sh "aws cloudformation delete-stack --region ${AWS_REGION} --stack-name ${APP_STACK_NAME}"
+ echo "Delete existing key pair using AWS CLI"
+ sh "aws ec2 delete-key-pair --region ${AWS_REGION} --key-name ${CFN_KEYPAIR}"
+ sh "rm -rf ${CFN_KEYPAIR}"
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/jenkins/jenkinsfile-petclinic-weekly-qa b/jenkins/jenkinsfile-petclinic-weekly-qa
new file mode 100644
index 0000000000..6a57e49144
--- /dev/null
+++ b/jenkins/jenkinsfile-petclinic-weekly-qa
@@ -0,0 +1,73 @@
+pipeline {
+ agent { label "master" }
+ environment {
+ PATH=sh(script:"echo $PATH:/usr/local/bin", returnStdout:true).trim()
+ APP_NAME="petclinic"
+ APP_REPO_NAME="huseyin-repo/petclinic-app-qa"
+ APP_STACK_NAME="Huseyin-petclinic-App-QA-1"
+ CFN_KEYPAIR="huseyin-petclinic-qa.key"
+ AWS_ACCOUNT_ID=sh(script:'export PATH="$PATH:/usr/local/bin" && aws sts get-caller-identity --query Account --output text', returnStdout:true).trim()
+ AWS_REGION="us-east-1"
+ ECR_REGISTRY="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
+ ANSIBLE_PRIVATE_KEY_FILE="${JENKINS_HOME}/.ssh/${CFN_KEYPAIR}"
+ ANSIBLE_HOST_KEY_CHECKING="False"
+ }
+ stages {
+ stage('Package Application') {
+ steps {
+ echo 'Packaging the app into jars with maven'
+ sh ". ./jenkins/package-with-maven-container.sh"
+ }
+ }
+ stage('Prepare Tags for Docker Images') {
+ steps {
+ echo 'Preparing Tags for Docker Images'
+ script {
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-admin-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_ADMIN_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:admin-server-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-api-gateway/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_API_GATEWAY="${ECR_REGISTRY}/${APP_REPO_NAME}:api-gateway-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-config-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_CONFIG_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:config-server-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-customers-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_CUSTOMERS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:customers-service-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-discovery-server/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_DISCOVERY_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:discovery-server-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-hystrix-dashboard/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_HYSTRIX_DASHBOARD="${ECR_REGISTRY}/${APP_REPO_NAME}:hystrix-dashboard-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-vets-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_VETS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:vets-service-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ MVN_VERSION=sh(script:'. ${WORKSPACE}/spring-petclinic-visits-service/target/maven-archiver/pom.properties && echo $version', returnStdout:true).trim()
+ env.IMAGE_TAG_VISITS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:visits-service-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+ env.IMAGE_TAG_GRAFANA_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:grafana-service"
+ env.IMAGE_TAG_PROMETHEUS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:prometheus-service"
+ }
+ }
+ }
+ stage('Build App Docker Images') {
+ steps {
+ echo 'Building App Dev Images'
+ sh ". ./jenkins/build-qa-docker-images-for-ecr.sh"
+ sh 'docker image ls'
+ }
+ }
+ stage('Push Images to ECR Repo') {
+ steps {
+ echo "Pushing ${APP_NAME} App Images to ECR Repo"
+ sh ". ./jenkins/push-qa-docker-images-to-ecr.sh"
+ }
+ }
+ stage('Deploy App on Docker Swarm'){
+ steps {
+ echo 'Deploying App on Swarm'
+ sh '. ./ansible/scripts/deploy_app_on_qa_environment.sh'
+ }
+ }
+ }
+ post {
+ always {
+ echo 'Deleting all local images'
+ sh 'docker image prune -af'
+ }
+ }
+}
\ No newline at end of file
diff --git a/jenkins/package-with-maven-container.sh b/jenkins/package-with-maven-container.sh
new file mode 100644
index 0000000000..6d691a5ed4
--- /dev/null
+++ b/jenkins/package-with-maven-container.sh
@@ -0,0 +1 @@
+docker run --rm -v $HOME/.m2:/root/.m2 -v $WORKSPACE:/app -w /app maven:3.6-openjdk-11 mvn clean package
\ No newline at end of file
diff --git a/jenkins/prepare-tags-ecr-for-dev-docker-images.sh b/jenkins/prepare-tags-ecr-for-dev-docker-images.sh
new file mode 100644
index 0000000000..8fff3dbf6d
--- /dev/null
+++ b/jenkins/prepare-tags-ecr-for-dev-docker-images.sh
@@ -0,0 +1,18 @@
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-admin-server/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_ADMIN_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:admin-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-api-gateway/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_API_GATEWAY="${ECR_REGISTRY}/${APP_REPO_NAME}:api-gateway-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-config-server/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_CONFIG_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:config-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-customers-service/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_CUSTOMERS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:customers-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-discovery-server/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_DISCOVERY_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:discovery-server-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-hystrix-dashboard/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_HYSTRIX_DASHBOARD="${ECR_REGISTRY}/${APP_REPO_NAME}:hystrix-dashboard-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-vets-service/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_VETS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:vets-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-visits-service/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_VISITS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:visits-service-v${MVN_VERSION}-b${BUILD_NUMBER}"
+export IMAGE_TAG_GRAFANA_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:grafana-service"
+export IMAGE_TAG_PROMETHEUS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:prometheus-service"
\ No newline at end of file
diff --git a/jenkins/prepare-tags-ecr-for-qa-docker-images.sh b/jenkins/prepare-tags-ecr-for-qa-docker-images.sh
new file mode 100644
index 0000000000..d90e8db9c2
--- /dev/null
+++ b/jenkins/prepare-tags-ecr-for-qa-docker-images.sh
@@ -0,0 +1,18 @@
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-admin-server/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_ADMIN_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:admin-server-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-api-gateway/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_API_GATEWAY="${ECR_REGISTRY}/${APP_REPO_NAME}:api-gateway-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-config-server/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_CONFIG_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:config-server-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-customers-service/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_CUSTOMERS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:customers-service-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-discovery-server/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_DISCOVERY_SERVER="${ECR_REGISTRY}/${APP_REPO_NAME}:discovery-server-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-hystrix-dashboard/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_HYSTRIX_DASHBOARD="${ECR_REGISTRY}/${APP_REPO_NAME}:hystrix-dashboard-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-vets-service/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_VETS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:vets-service-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+MVN_VERSION=$(. ${WORKSPACE}/spring-petclinic-visits-service/target/maven-archiver/pom.properties && echo $version)
+export IMAGE_TAG_VISITS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:visits-service-qa-v${MVN_VERSION}-b${BUILD_NUMBER}"
+export IMAGE_TAG_GRAFANA_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:grafana-service"
+export IMAGE_TAG_PROMETHEUS_SERVICE="${ECR_REGISTRY}/${APP_REPO_NAME}:prometheus-service"
\ No newline at end of file
diff --git a/jenkins/push-dev-docker-images-to-ecr.sh b/jenkins/push-dev-docker-images-to-ecr.sh
new file mode 100644
index 0000000000..7ae5bfdfde
--- /dev/null
+++ b/jenkins/push-dev-docker-images-to-ecr.sh
@@ -0,0 +1,11 @@
+aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ECR_REGISTRY}
+docker push "${IMAGE_TAG_ADMIN_SERVER}"
+docker push "${IMAGE_TAG_API_GATEWAY}"
+docker push "${IMAGE_TAG_CONFIG_SERVER}"
+docker push "${IMAGE_TAG_CUSTOMERS_SERVICE}"
+docker push "${IMAGE_TAG_DISCOVERY_SERVER}"
+docker push "${IMAGE_TAG_HYSTRIX_DASHBOARD}"
+docker push "${IMAGE_TAG_VETS_SERVICE}"
+docker push "${IMAGE_TAG_VISITS_SERVICE}"
+docker push "${IMAGE_TAG_GRAFANA_SERVICE}"
+docker push "${IMAGE_TAG_PROMETHEUS_SERVICE}"
\ No newline at end of file
diff --git a/k8s/base/admin-server-deployment.yaml b/k8s/base/admin-server-deployment.yaml
new file mode 100644
index 0000000000..fa936fb8ff
--- /dev/null
+++ b/k8s/base/admin-server-deployment.yaml
@@ -0,0 +1,41 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: admin-server
+ name: admin-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ io.kompose.service: admin-server
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: admin-server
+ spec:
+ containers:
+ - image: IMAGE_TAG_ADMIN_SERVER
+ name: admin-server
+ ports:
+ - containerPort: 9090
+ resources: {}
+ initContainers:
+ - name: init-discovery-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z discovery-server:8761; do echo waiting for discovery-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/admin-server-service.yaml b/k8s/base/admin-server-service.yaml
new file mode 100644
index 0000000000..d51aae79c9
--- /dev/null
+++ b/k8s/base/admin-server-service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: admin-server
+ name: admin-server
+spec:
+ ports:
+ - name: "9090"
+ port: 9090
+ targetPort: 9090
+ selector:
+ io.kompose.service: admin-server
+status:
+ loadBalancer: {}
diff --git a/k8s/base/api-gateway-deployment.yaml b/k8s/base/api-gateway-deployment.yaml
new file mode 100644
index 0000000000..3c39d39889
--- /dev/null
+++ b/k8s/base/api-gateway-deployment.yaml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: api-gateway
+ name: api-gateway
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ io.kompose.service: api-gateway
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: api-gateway
+ spec:
+ containers:
+ - image: IMAGE_TAG_API_GATEWAY
+ name: api-gateway
+ ports:
+ - containerPort: 8080
+ resources: {}
+ initContainers:
+ - name: init-discovery-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z discovery-server:8761; do echo waiting for discovery-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/api-gateway-ingress.yaml b/k8s/base/api-gateway-ingress.yaml
new file mode 100644
index 0000000000..64612b9038
--- /dev/null
+++ b/k8s/base/api-gateway-ingress.yaml
@@ -0,0 +1,22 @@
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: api-gateway
+ name: api-gateway
+spec:
+ rules:
+ - host: petclinic.clarusway.us
+ http:
+ paths:
+ - backend:
+ serviceName: api-gateway
+ servicePort: 8080
+status:
+ loadBalancer: {}
diff --git a/k8s/base/api-gateway-service.yaml b/k8s/base/api-gateway-service.yaml
new file mode 100644
index 0000000000..9674c75d04
--- /dev/null
+++ b/k8s/base/api-gateway-service.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: api-gateway
+ name: api-gateway
+spec:
+ ports:
+ - name: "8080"
+ port: 8080
+ targetPort: 8080
+ selector:
+ io.kompose.service: api-gateway
+status:
+ loadBalancer: {}
diff --git a/k8s/base/config-server-deployment.yaml b/k8s/base/config-server-deployment.yaml
new file mode 100644
index 0000000000..aa5b54436a
--- /dev/null
+++ b/k8s/base/config-server-deployment.yaml
@@ -0,0 +1,37 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: config-server
+ name: config-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ io.kompose.service: config-server
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: config-server
+ spec:
+ containers:
+ - image: IMAGE_TAG_CONFIG_SERVER
+ name: config-server
+ ports:
+ - containerPort: 8888
+ resources: {}
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/config-server-service.yaml b/k8s/base/config-server-service.yaml
new file mode 100644
index 0000000000..e990afb1dc
--- /dev/null
+++ b/k8s/base/config-server-service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: config-server
+ name: config-server
+spec:
+ ports:
+ - name: "8888"
+ port: 8888
+ targetPort: 8888
+ selector:
+ io.kompose.service: config-server
+status:
+ loadBalancer: {}
diff --git a/k8s/base/customers-service-deployment.yaml b/k8s/base/customers-service-deployment.yaml
new file mode 100644
index 0000000000..f4eb9dc892
--- /dev/null
+++ b/k8s/base/customers-service-deployment.yaml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: customers-service
+ name: customers-service
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ io.kompose.service: customers-service
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: customers-service
+ spec:
+ containers:
+ - image: IMAGE_TAG_CUSTOMERS_SERVICE
+ name: customers-service
+ ports:
+ - containerPort: 8081
+ resources: {}
+ initContainers:
+ - name: init-discovery-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z discovery-server:8761; do echo waiting for discovery-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/customers-service-ingress.yaml b/k8s/base/customers-service-ingress.yaml
new file mode 100644
index 0000000000..716a7a6945
--- /dev/null
+++ b/k8s/base/customers-service-ingress.yaml
@@ -0,0 +1,22 @@
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: customers-service
+ name: customers-service
+spec:
+ rules:
+ - host: petclinic.clarusway.us
+ http:
+ paths:
+ - backend:
+ serviceName: customers-service
+ servicePort: 8081
+status:
+ loadBalancer: {}
diff --git a/k8s/base/customers-service-service.yaml b/k8s/base/customers-service-service.yaml
new file mode 100644
index 0000000000..aac4e3c552
--- /dev/null
+++ b/k8s/base/customers-service-service.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: customers-service
+ name: customers-service
+spec:
+ ports:
+ - name: "8081"
+ port: 8081
+ targetPort: 8081
+ selector:
+ io.kompose.service: customers-service
+status:
+ loadBalancer: {}
diff --git a/k8s/base/discovery-server-deployment.yaml b/k8s/base/discovery-server-deployment.yaml
new file mode 100644
index 0000000000..cb38b77ef2
--- /dev/null
+++ b/k8s/base/discovery-server-deployment.yaml
@@ -0,0 +1,41 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: discovery-server
+ name: discovery-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ io.kompose.service: discovery-server
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: discovery-server
+ spec:
+ containers:
+ - image: IMAGE_TAG_DISCOVERY_SERVER
+ name: discovery-server
+ ports:
+ - containerPort: 8761
+ resources: {}
+ initContainers:
+ - name: init-config-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z config-server:8888; do echo waiting for config-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/discovery-server-service.yaml b/k8s/base/discovery-server-service.yaml
new file mode 100644
index 0000000000..071e97ad1f
--- /dev/null
+++ b/k8s/base/discovery-server-service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: discovery-server
+ name: discovery-server
+spec:
+ ports:
+ - name: "8761"
+ port: 8761
+ targetPort: 8761
+ selector:
+ io.kompose.service: discovery-server
+status:
+ loadBalancer: {}
diff --git a/k8s/base/grafana-server-deployment.yaml b/k8s/base/grafana-server-deployment.yaml
new file mode 100644
index 0000000000..ef95843478
--- /dev/null
+++ b/k8s/base/grafana-server-deployment.yaml
@@ -0,0 +1,41 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: grafana-server
+ name: grafana-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ io.kompose.service: grafana-server
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: grafana-server
+ spec:
+ containers:
+ - image: IMAGE_TAG_GRAFANA_SERVICE
+ name: grafana-server
+ ports:
+ - containerPort: 3000
+ resources: {}
+ initContainers:
+ - name: init-discovery-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z discovery-server:8761; do echo waiting for discovery-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/grafana-server-service.yaml b/k8s/base/grafana-server-service.yaml
new file mode 100644
index 0000000000..fabc03aedf
--- /dev/null
+++ b/k8s/base/grafana-server-service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: grafana-server
+ name: grafana-server
+spec:
+ ports:
+ - name: "3000"
+ port: 3000
+ targetPort: 3000
+ selector:
+ io.kompose.service: grafana-server
+status:
+ loadBalancer: {}
diff --git a/k8s/base/hystrix-dashboard-deployment.yaml b/k8s/base/hystrix-dashboard-deployment.yaml
new file mode 100644
index 0000000000..2a7c6df14f
--- /dev/null
+++ b/k8s/base/hystrix-dashboard-deployment.yaml
@@ -0,0 +1,41 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: hystrix-dashboard
+ name: hystrix-dashboard
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ io.kompose.service: hystrix-dashboard
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: hystrix-dashboard
+ spec:
+ containers:
+ - image: IMAGE_TAG_HYSTRIX_DASHBOARD
+ name: hystrix-dashboard
+ ports:
+ - containerPort: 7979
+ resources: {}
+ initContainers:
+ - name: init-discovery-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z discovery-server:8761; do echo waiting for discovery-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/hystrix-dashboard-service.yaml b/k8s/base/hystrix-dashboard-service.yaml
new file mode 100644
index 0000000000..50c22dc7c2
--- /dev/null
+++ b/k8s/base/hystrix-dashboard-service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: hystrix-dashboard
+ name: hystrix-dashboard
+spec:
+ ports:
+ - name: "7979"
+ port: 7979
+ targetPort: 7979
+ selector:
+ io.kompose.service: hystrix-dashboard
+status:
+ loadBalancer: {}
diff --git a/k8s/base/kustomization-template.yml b/k8s/base/kustomization-template.yml
new file mode 100644
index 0000000000..dbbe312b06
--- /dev/null
+++ b/k8s/base/kustomization-template.yml
@@ -0,0 +1,49 @@
+resources:
+- admin-server-deployment.yaml
+- api-gateway-deployment.yaml
+- config-server-deployment.yaml
+- customers-service-deployment.yaml
+- discovery-server-deployment.yaml
+- grafana-server-deployment.yaml
+- hystrix-dashboard-deployment.yaml
+- prometheus-server-deployment.yaml
+- tracing-server-deployment.yaml
+- vets-service-deployment.yaml
+- visits-service-deployment.yaml
+- admin-server-service.yaml
+- api-gateway-service.yaml
+- config-server-service.yaml
+- customers-service-service.yaml
+- discovery-server-service.yaml
+- grafana-server-service.yaml
+- hystrix-dashboard-service.yaml
+- prometheus-server-service.yaml
+- tracing-server-service.yaml
+- vets-service-service.yaml
+- visits-service-service.yaml
+- api-gateway-ingress.yaml
+- customers-service-ingress.yaml
+- vets-service-ingress.yaml
+- visits-service-ingress.yaml
+
+images:
+- name: IMAGE_TAG_CONFIG_SERVER
+ newName: "${IMAGE_TAG_CONFIG_SERVER}"
+- name: IMAGE_TAG_DISCOVERY_SERVER
+ newName: "${IMAGE_TAG_DISCOVERY_SERVER}"
+- name: IMAGE_TAG_CUSTOMERS_SERVICE
+ newName: "${IMAGE_TAG_CUSTOMERS_SERVICE}"
+- name: IMAGE_TAG_VISITS_SERVICE
+ newName: "${IMAGE_TAG_VISITS_SERVICE}"
+- name: IMAGE_TAG_VETS_SERVICE
+ newName: "${IMAGE_TAG_VETS_SERVICE}"
+- name: IMAGE_TAG_API_GATEWAY
+ newName: "${IMAGE_TAG_API_GATEWAY}"
+- name: IMAGE_TAG_ADMIN_SERVER
+ newName: "${IMAGE_TAG_ADMIN_SERVER}"
+- name: IMAGE_TAG_HYSTRIX_DASHBOARD
+ newName: "${IMAGE_TAG_HYSTRIX_DASHBOARD}"
+- name: IMAGE_TAG_GRAFANA_SERVICE
+ newName: "${IMAGE_TAG_GRAFANA_SERVICE}"
+- name: IMAGE_TAG_PROMETHEUS_SERVICE
+ newName: "${IMAGE_TAG_PROMETHEUS_SERVICE}"
\ No newline at end of file
diff --git a/k8s/base/kustomization.yml b/k8s/base/kustomization.yml
new file mode 100644
index 0000000000..1fcd183677
--- /dev/null
+++ b/k8s/base/kustomization.yml
@@ -0,0 +1,49 @@
+resources:
+- admin-server-deployment.yaml
+- api-gateway-deployment.yaml
+- config-server-deployment.yaml
+- customers-service-deployment.yaml
+- discovery-server-deployment.yaml
+- grafana-server-deployment.yaml
+- hystrix-dashboard-deployment.yaml
+- prometheus-server-deployment.yaml
+- tracing-server-deployment.yaml
+- vets-service-deployment.yaml
+- visits-service-deployment.yaml
+- admin-server-service.yaml
+- api-gateway-service.yaml
+- config-server-service.yaml
+- customers-service-service.yaml
+- discovery-server-service.yaml
+- grafana-server-service.yaml
+- hystrix-dashboard-service.yaml
+- prometheus-server-service.yaml
+- tracing-server-service.yaml
+- vets-service-service.yaml
+- visits-service-service.yaml
+- api-gateway-ingress.yaml
+- customers-service-ingress.yaml
+- vets-service-ingress.yaml
+- visits-service-ingress.yaml
+
+images:
+- name: IMAGE_TAG_CONFIG_SERVER
+ newName: "testing-image-1"
+- name: IMAGE_TAG_DISCOVERY_SERVER
+ newName: "testing-image-2"
+- name: IMAGE_TAG_CUSTOMERS_SERVICE
+ newName: "testing-image-3"
+- name: IMAGE_TAG_VISITS_SERVICE
+ newName: "testing-image-4"
+- name: IMAGE_TAG_VETS_SERVICE
+ newName: "testing-image-5"
+- name: IMAGE_TAG_API_GATEWAY
+ newName: "testing-image-6"
+- name: IMAGE_TAG_ADMIN_SERVER
+ newName: "testing-image-7"
+- name: IMAGE_TAG_HYSTRIX_DASHBOARD
+ newName: "testing-image-8"
+- name: IMAGE_TAG_GRAFANA_SERVICE
+ newName: "testing-image-9"
+- name: IMAGE_TAG_PROMETHEUS_SERVICE
+ newName: "testing-image-10"
\ No newline at end of file
diff --git a/k8s/base/prometheus-server-deployment.yaml b/k8s/base/prometheus-server-deployment.yaml
new file mode 100644
index 0000000000..ffacc07f31
--- /dev/null
+++ b/k8s/base/prometheus-server-deployment.yaml
@@ -0,0 +1,41 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: prometheus-server
+ name: prometheus-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ io.kompose.service: prometheus-server
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: prometheus-server
+ spec:
+ containers:
+ - image: IMAGE_TAG_PROMETHEUS_SERVICE
+ name: prometheus-server
+ ports:
+ - containerPort: 9090
+ resources: {}
+ initContainers:
+ - name: init-discovery-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z discovery-server:8761; do echo waiting for discovery-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/prometheus-server-service.yaml b/k8s/base/prometheus-server-service.yaml
new file mode 100644
index 0000000000..105d6aa454
--- /dev/null
+++ b/k8s/base/prometheus-server-service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: prometheus-server
+ name: prometheus-server
+spec:
+ ports:
+ - name: "9091"
+ port: 9091
+ targetPort: 9090
+ selector:
+ io.kompose.service: prometheus-server
+status:
+ loadBalancer: {}
diff --git a/k8s/base/tracing-server-deployment.yaml b/k8s/base/tracing-server-deployment.yaml
new file mode 100644
index 0000000000..563293c718
--- /dev/null
+++ b/k8s/base/tracing-server-deployment.yaml
@@ -0,0 +1,36 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: tracing-server
+ name: tracing-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ io.kompose.service: tracing-server
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: tracing-server
+ spec:
+ containers:
+ - env:
+ - name: JAVA_OPTS
+ value: -XX:+UnlockExperimentalVMOptions -Djava.security.egd=file:/dev/./urandom
+ image: openzipkin/zipkin
+ name: tracing-server
+ ports:
+ - containerPort: 9411
+ resources: {}
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/tracing-server-service.yaml b/k8s/base/tracing-server-service.yaml
new file mode 100644
index 0000000000..7bdabd2e6a
--- /dev/null
+++ b/k8s/base/tracing-server-service.yaml
@@ -0,0 +1,19 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: tracing-server
+ name: tracing-server
+spec:
+ ports:
+ - name: "9411"
+ port: 9411
+ targetPort: 9411
+ selector:
+ io.kompose.service: tracing-server
+status:
+ loadBalancer: {}
diff --git a/k8s/base/vets-service-deployment.yaml b/k8s/base/vets-service-deployment.yaml
new file mode 100644
index 0000000000..4e29396e6f
--- /dev/null
+++ b/k8s/base/vets-service-deployment.yaml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: vets-service
+ name: vets-service
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ io.kompose.service: vets-service
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: vets-service
+ spec:
+ containers:
+ - image: IMAGE_TAG_VETS_SERVICE
+ name: vets-service
+ ports:
+ - containerPort: 8083
+ resources: {}
+ initContainers:
+ - name: init-discovery-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z discovery-server:8761; do echo waiting for discovery-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/vets-service-ingress.yaml b/k8s/base/vets-service-ingress.yaml
new file mode 100644
index 0000000000..06a1894096
--- /dev/null
+++ b/k8s/base/vets-service-ingress.yaml
@@ -0,0 +1,22 @@
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: vets-service
+ name: vets-service
+spec:
+ rules:
+ - host: petclinic.clarusway.us
+ http:
+ paths:
+ - backend:
+ serviceName: vets-service
+ servicePort: 8083
+status:
+ loadBalancer: {}
diff --git a/k8s/base/vets-service-service.yaml b/k8s/base/vets-service-service.yaml
new file mode 100644
index 0000000000..6444738246
--- /dev/null
+++ b/k8s/base/vets-service-service.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: vets-service
+ name: vets-service
+spec:
+ ports:
+ - name: "8083"
+ port: 8083
+ targetPort: 8083
+ selector:
+ io.kompose.service: vets-service
+status:
+ loadBalancer: {}
diff --git a/k8s/base/visits-service-deployment.yaml b/k8s/base/visits-service-deployment.yaml
new file mode 100644
index 0000000000..5e48933d2d
--- /dev/null
+++ b/k8s/base/visits-service-deployment.yaml
@@ -0,0 +1,43 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: visits-service
+ name: visits-service
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ io.kompose.service: visits-service
+ strategy: {}
+ template:
+ metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: visits-service
+ spec:
+ containers:
+ - image: IMAGE_TAG_VISITS_SERVICE
+ name: visits-service
+ ports:
+ - containerPort: 8082
+ resources: {}
+ initContainers:
+ - name: init-discovery-server
+ image: busybox
+ command: ['sh', '-c', 'until nc -z discovery-server:8761; do echo waiting for discovery-server; sleep 2; done;']
+ imagePullSecrets:
+ - name: regcred
+ restartPolicy: Always
+status: {}
diff --git a/k8s/base/visits-service-ingress.yaml b/k8s/base/visits-service-ingress.yaml
new file mode 100644
index 0000000000..9d7378d62d
--- /dev/null
+++ b/k8s/base/visits-service-ingress.yaml
@@ -0,0 +1,22 @@
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: visits-service
+ name: visits-service
+spec:
+ rules:
+ - host: petclinic.clarusway.us
+ http:
+ paths:
+ - backend:
+ serviceName: visits-service
+ servicePort: 8082
+status:
+ loadBalancer: {}
diff --git a/k8s/base/visits-service-service.yaml b/k8s/base/visits-service-service.yaml
new file mode 100644
index 0000000000..730910dd3c
--- /dev/null
+++ b/k8s/base/visits-service-service.yaml
@@ -0,0 +1,21 @@
+apiVersion: v1
+kind: Service
+metadata:
+ annotations:
+ kompose.cmd: kompose convert -f docker-compose.yml -o base
+ kompose.image-pull-secret: regcred
+ kompose.service.expose: petclinic.clarusway.us
+ kompose.version: 1.22.0 (955b78124)
+ creationTimestamp: null
+ labels:
+ io.kompose.service: visits-service
+ name: visits-service
+spec:
+ ports:
+ - name: "8082"
+ port: 8082
+ targetPort: 8082
+ selector:
+ io.kompose.service: visits-service
+status:
+ loadBalancer: {}
diff --git a/k8s/docker-compose.yml b/k8s/docker-compose.yml
new file mode 100644
index 0000000000..f31dbad415
--- /dev/null
+++ b/k8s/docker-compose.yml
@@ -0,0 +1,80 @@
+version: '3'
+services:
+ config-server:
+ image: IMAGE_TAG_CONFIG_SERVER
+ ports:
+ - 8888:8888
+ labels:
+ kompose.image-pull-secret: "regcred"
+ discovery-server:
+ image: IMAGE_TAG_DISCOVERY_SERVER
+ ports:
+ - 8761:8761
+ labels:
+ kompose.image-pull-secret: "regcred"
+ customers-service:
+ image: IMAGE_TAG_CUSTOMERS_SERVICE
+ deploy:
+ replicas: 2
+ ports:
+ - 8081:8081
+ labels:
+ kompose.image-pull-secret: "regcred"
+ kompose.service.expose: "petclinic.clarusway.us"
+ visits-service:
+ image: IMAGE_TAG_VISITS_SERVICE
+ deploy:
+ replicas: 2
+ ports:
+ - 8082:8082
+ labels:
+ kompose.image-pull-secret: "regcred"
+ kompose.service.expose: "petclinic.clarusway.us"
+ vets-service:
+ image: IMAGE_TAG_VETS_SERVICE
+ deploy:
+ replicas: 2
+ ports:
+ - 8083:8083
+ labels:
+ kompose.image-pull-secret: "regcred"
+ kompose.service.expose: "petclinic.clarusway.us"
+ api-gateway:
+ image: IMAGE_TAG_API_GATEWAY
+ deploy:
+ replicas: 2
+ ports:
+ - 8080:8080
+ labels:
+ kompose.image-pull-secret: "regcred"
+ kompose.service.expose: "petclinic.clarusway.us"
+ tracing-server:
+ image: openzipkin/zipkin
+ environment:
+ - JAVA_OPTS=-XX:+UnlockExperimentalVMOptions -Djava.security.egd=file:/dev/./urandom
+ ports:
+ - 9411:9411
+ admin-server:
+ image: IMAGE_TAG_ADMIN_SERVER
+ ports:
+ - 9090:9090
+ labels:
+ kompose.image-pull-secret: "regcred"
+ hystrix-dashboard:
+ image: IMAGE_TAG_HYSTRIX_DASHBOARD
+ ports:
+ - 7979:7979
+ labels:
+ kompose.image-pull-secret: "regcred"
+ grafana-server:
+ image: IMAGE_TAG_GRAFANA_SERVICE
+ ports:
+ - 3000:3000
+ labels:
+ kompose.image-pull-secret: "regcred"
+ prometheus-server:
+ image: IMAGE_TAG_PROMETHEUS_SERVICE
+ ports:
+ - 9091:9090
+ labels:
+ kompose.image-pull-secret: "regcred"
\ No newline at end of file
diff --git a/k8s/prod/kustomization.yml b/k8s/prod/kustomization.yml
new file mode 100644
index 0000000000..0734bdc214
--- /dev/null
+++ b/k8s/prod/kustomization.yml
@@ -0,0 +1,6 @@
+# kustomization.yml
+namespace: "petclinic-prod-ns"
+bases:
+- ../base
+patches:
+- replica-count.yml
\ No newline at end of file
diff --git a/k8s/prod/replica-count.yml b/k8s/prod/replica-count.yml
new file mode 100644
index 0000000000..74cd993bb1
--- /dev/null
+++ b/k8s/prod/replica-count.yml
@@ -0,0 +1,7 @@
+# replica-count.yml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: api-gateway
+spec:
+ replicas: 5
\ No newline at end of file
diff --git a/k8s/staging/kustomization.yml b/k8s/staging/kustomization.yml
new file mode 100644
index 0000000000..80d4c1be96
--- /dev/null
+++ b/k8s/staging/kustomization.yml
@@ -0,0 +1,6 @@
+# kustomization.yml
+namespace: "petclinic-staging-ns"
+bases:
+- ../base
+patches:
+- replica-count.yml
\ No newline at end of file
diff --git a/k8s/staging/replica-count.yml b/k8s/staging/replica-count.yml
new file mode 100644
index 0000000000..e9a4bb5edf
--- /dev/null
+++ b/k8s/staging/replica-count.yml
@@ -0,0 +1,7 @@
+# replica-count.yml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: api-gateway
+spec:
+ replicas: 3
\ No newline at end of file
diff --git a/package-with-mvn-wrapper.sh b/package-with-mvn-wrapper.sh
new file mode 100644
index 0000000000..ab98051854
--- /dev/null
+++ b/package-with-mvn-wrapper.sh
@@ -0,0 +1,2 @@
+# package-with-mvn-wrapper.sh
+./mvnw clean package
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index da42b9ce94..e1ddfe6dfb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -129,6 +129,26 @@
false
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.2
+
+
+
+ prepare-agent
+
+
+
+
+ report
+ test
+
+ report
+
+
+
+
diff --git a/selenium-jobs/dummy_selenium_test_headless.py b/selenium-jobs/dummy_selenium_test_headless.py
new file mode 100644
index 0000000000..05d9c12dcc
--- /dev/null
+++ b/selenium-jobs/dummy_selenium_test_headless.py
@@ -0,0 +1,14 @@
+from selenium import webdriver
+chrome_options = webdriver.ChromeOptions()
+chrome_options.add_argument("headless")
+chrome_options.add_argument("no-sandbox")
+chrome_options.add_argument("disable-dev-shm-usage")
+driver = webdriver.Chrome(options=chrome_options)
+base_url = "https://www.google.com/"
+driver.get(base_url)
+source = driver.page_source
+if "I'm Feeling Lucky" in source:
+ print("Test passed")
+else:
+ print("Test failed")
+driver.close()
\ No newline at end of file
diff --git a/selenium-jobs/test_owners_all_headless.py b/selenium-jobs/test_owners_all_headless.py
new file mode 100644
index 0000000000..578872b94d
--- /dev/null
+++ b/selenium-jobs/test_owners_all_headless.py
@@ -0,0 +1,29 @@
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+from time import sleep
+import os
+# Set chrome options for working with headless mode (no screen)
+chrome_options = webdriver.ChromeOptions()
+chrome_options.add_argument("headless")
+chrome_options.add_argument("no-sandbox")
+chrome_options.add_argument("disable-dev-shm-usage")
+# Update webdriver instance of chrome-driver with adding chrome options
+driver = webdriver.Chrome(options=chrome_options)
+# Connect to the application
+APP_IP = os.environ['MASTER_PUBLIC_IP']
+url = "http://"+APP_IP.strip()+":8080/"
+print(url)
+driver.get(url)
+owners_link = driver.find_element_by_link_text("OWNERS")
+owners_link.click()
+sleep(2)
+all_link = driver.find_element_by_link_text("ALL")
+all_link.click()
+sleep(2)
+# Verify that table loaded
+sleep(1)
+verify_table = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, "table")))
+print("Table loaded")
+driver.quit()
\ No newline at end of file
diff --git a/selenium-jobs/test_owners_register_headless.py b/selenium-jobs/test_owners_register_headless.py
new file mode 100644
index 0000000000..85135d98cf
--- /dev/null
+++ b/selenium-jobs/test_owners_register_headless.py
@@ -0,0 +1,46 @@
+from selenium import webdriver
+from selenium.webdriver.common.keys import Keys
+from time import sleep
+import random
+import os
+# Set chrome options for working with headless mode (no screen)
+chrome_options = webdriver.ChromeOptions()
+chrome_options.add_argument("headless")
+chrome_options.add_argument("no-sandbox")
+chrome_options.add_argument("disable-dev-shm-usage")
+# Update webdriver instance of chrome-driver with adding chrome options
+driver = webdriver.Chrome(options=chrome_options)
+# Connect to the application
+APP_IP = os.environ['MASTER_PUBLIC_IP']
+url = "http://"+APP_IP.strip()+":8080/"
+print(url)
+driver.get(url)
+owners_link = driver.find_element_by_link_text("OWNERS")
+owners_link.click()
+sleep(2)
+all_link = driver.find_element_by_link_text("REGISTER")
+all_link.click()
+sleep(2)
+# Register new Owner to Petclinic App
+fn_field = driver.find_element_by_name('firstName')
+fn = 'Callahan' + str(random.randint(0, 100))
+fn_field.send_keys(fn)
+fn_field = driver.find_element_by_name('lastName')
+fn_field.send_keys('Clarusway')
+fn_field = driver.find_element_by_name('address')
+fn_field.send_keys('Ridge Corp. Street')
+fn_field = driver.find_element_by_name('city')
+fn_field.send_keys('McLean')
+fn_field = driver.find_element_by_name('telephone')
+fn_field.send_keys('+1230576803')
+fn_field.send_keys(Keys.ENTER)
+# Wait 1 second to get updated Owner List
+sleep(2)
+# Verify that new user is added to Owner List
+if fn in driver.page_source:
+ print(fn, 'is added and found in the Owners Table')
+ print("Test Passed")
+else:
+ print(fn, 'is not found in the Owners Table')
+ print("Test Failed")
+driver.quit()
\ No newline at end of file
diff --git a/selenium-jobs/test_veterinarians_headless.py b/selenium-jobs/test_veterinarians_headless.py
new file mode 100644
index 0000000000..fc6958c3cd
--- /dev/null
+++ b/selenium-jobs/test_veterinarians_headless.py
@@ -0,0 +1,25 @@
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+from time import sleep
+import os
+# Set chrome options for working with headless mode (no screen)
+chrome_options = webdriver.ChromeOptions()
+chrome_options.add_argument("headless")
+chrome_options.add_argument("no-sandbox")
+chrome_options.add_argument("disable-dev-shm-usage")
+# Update webdriver instance of chrome-driver with adding chrome options
+driver = webdriver.Chrome(options=chrome_options)
+# Connect to the application
+APP_IP = os.environ['MASTER_PUBLIC_IP']
+url = "http://"+APP_IP.strip()+":8080/"
+print(url)
+driver.get(url)
+vet_link = driver.find_element_by_link_text("VETERINARIANS")
+vet_link.click()
+# Verify that table loaded
+sleep(1)
+verify_table = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, "table")))
+print("Table loaded")
+driver.quit()
\ No newline at end of file
diff --git a/spring-petclinic-admin-server/Dockerfile b/spring-petclinic-admin-server/Dockerfile
new file mode 100644
index 0000000000..f00c9731a5
--- /dev/null
+++ b/spring-petclinic-admin-server/Dockerfile
@@ -0,0 +1,11 @@
+FROM openjdk:11-jre
+ARG DOCKERIZE_VERSION=v0.6.1
+ARG EXPOSED_PORT=9090
+ENV SPRING_PROFILES_ACTIVE docker
+ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz dockerize.tar.gz
+RUN tar xzf dockerize.tar.gz
+RUN chmod +x dockerize
+ADD ./target/*.jar /app.jar
+EXPOSE ${EXPOSED_PORT}
+ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
+
diff --git a/spring-petclinic-api-gateway/Dockerfile b/spring-petclinic-api-gateway/Dockerfile
new file mode 100644
index 0000000000..c5820520a5
--- /dev/null
+++ b/spring-petclinic-api-gateway/Dockerfile
@@ -0,0 +1,11 @@
+FROM openjdk:11-jre
+ARG DOCKERIZE_VERSION=v0.6.1
+ARG EXPOSED_PORT=8080
+ENV SPRING_PROFILES_ACTIVE docker
+ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz dockerize.tar.gz
+RUN tar xzf dockerize.tar.gz
+RUN chmod +x dockerize
+ADD ./target/*.jar /app.jar
+EXPOSE ${EXPOSED_PORT}
+ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
+
diff --git a/spring-petclinic-config-server/Dockerfile b/spring-petclinic-config-server/Dockerfile
new file mode 100644
index 0000000000..365b88e105
--- /dev/null
+++ b/spring-petclinic-config-server/Dockerfile
@@ -0,0 +1,11 @@
+FROM openjdk:11-jre
+ARG DOCKERIZE_VERSION=v0.6.1
+ARG EXPOSED_PORT=8888
+ENV SPRING_PROFILES_ACTIVE docker
+ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz dockerize.tar.gz
+RUN tar xzf dockerize.tar.gz
+RUN chmod +x dockerize
+ADD ./target/*.jar /app.jar
+EXPOSE ${EXPOSED_PORT}
+ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
+
diff --git a/spring-petclinic-customers-service/Dockerfile b/spring-petclinic-customers-service/Dockerfile
new file mode 100644
index 0000000000..b1c1e0c8cd
--- /dev/null
+++ b/spring-petclinic-customers-service/Dockerfile
@@ -0,0 +1,11 @@
+FROM openjdk:11-jre
+ARG DOCKERIZE_VERSION=v0.6.1
+ARG EXPOSED_PORT=8081
+ENV SPRING_PROFILES_ACTIVE docker
+ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz dockerize.tar.gz
+RUN tar xzf dockerize.tar.gz
+RUN chmod +x dockerize
+ADD ./target/*.jar /app.jar
+EXPOSE ${EXPOSED_PORT}
+ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
+
diff --git a/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/model/PetTest.java b/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/model/PetTest.java
new file mode 100644
index 0000000000..2a6380fbcf
--- /dev/null
+++ b/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/model/PetTest.java
@@ -0,0 +1,39 @@
+package org.springframework.samples.petclinic.customers.model;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Date;
+
+import org.junit.jupiter.api.Test;
+public class PetTest {
+ @Test
+ public void testGetName(){
+ //Arrange
+ Pet pet = new Pet();
+ //Act
+ pet.setName("Fluffy");
+ //Assert
+ assertEquals("Fluffy", pet.getName());
+ }
+ @Test
+ public void testGetOwner(){
+ //Arrange
+ Pet pet = new Pet();
+ Owner owner = new Owner();
+ owner.setFirstName("Call");
+ //Act
+ pet.setOwner(owner);
+ //Assert
+ assertEquals("Call", pet.getOwner().getFirstName());
+ }
+ @Test
+ public void testBirthDate(){
+ //Arrange
+ Pet pet = new Pet();
+ Date bd = new Date();
+ //Act
+ pet.setBirthDate(bd);
+ //Assert
+ assertEquals(bd,pet.getBirthDate());
+ }
+}
diff --git a/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/PetResourceTest.java b/spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/web/PetResourceTest.java
similarity index 100%
rename from spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/PetResourceTest.java
rename to spring-petclinic-customers-service/src/test/java/org/springframework/samples/petclinic/customers/web/web/PetResourceTest.java
diff --git a/spring-petclinic-discovery-server/Dockerfile b/spring-petclinic-discovery-server/Dockerfile
new file mode 100644
index 0000000000..4b2ef3dd87
--- /dev/null
+++ b/spring-petclinic-discovery-server/Dockerfile
@@ -0,0 +1,11 @@
+FROM openjdk:11-jre
+ARG DOCKERIZE_VERSION=v0.6.1
+ARG EXPOSED_PORT=8761
+ENV SPRING_PROFILES_ACTIVE docker
+ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz dockerize.tar.gz
+RUN tar xzf dockerize.tar.gz
+RUN chmod +x dockerize
+ADD ./target/*.jar /app.jar
+EXPOSE ${EXPOSED_PORT}
+ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
+
diff --git a/spring-petclinic-hystrix-dashboard/Dockerfile b/spring-petclinic-hystrix-dashboard/Dockerfile
new file mode 100644
index 0000000000..db170a937c
--- /dev/null
+++ b/spring-petclinic-hystrix-dashboard/Dockerfile
@@ -0,0 +1,11 @@
+FROM openjdk:11-jre
+ARG DOCKERIZE_VERSION=v0.6.1
+ARG EXPOSED_PORT=7979
+ENV SPRING_PROFILES_ACTIVE docker
+ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz dockerize.tar.gz
+RUN tar xzf dockerize.tar.gz
+RUN chmod +x dockerize
+ADD ./target/*.jar /app.jar
+EXPOSE ${EXPOSED_PORT}
+ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
+
diff --git a/spring-petclinic-vets-service/Dockerfile b/spring-petclinic-vets-service/Dockerfile
new file mode 100644
index 0000000000..40df3f0817
--- /dev/null
+++ b/spring-petclinic-vets-service/Dockerfile
@@ -0,0 +1,11 @@
+FROM openjdk:11-jre
+ARG DOCKERIZE_VERSION=v0.6.1
+ARG EXPOSED_PORT=8083
+ENV SPRING_PROFILES_ACTIVE docker
+ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz dockerize.tar.gz
+RUN tar xzf dockerize.tar.gz
+RUN chmod +x dockerize
+ADD ./target/*.jar /app.jar
+EXPOSE ${EXPOSED_PORT}
+ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
+
diff --git a/spring-petclinic-visits-service/Dockerfile b/spring-petclinic-visits-service/Dockerfile
new file mode 100644
index 0000000000..09c9126fbd
--- /dev/null
+++ b/spring-petclinic-visits-service/Dockerfile
@@ -0,0 +1,11 @@
+FROM openjdk:11-jre
+ARG DOCKERIZE_VERSION=v0.6.1
+ARG EXPOSED_PORT=8082
+ENV SPRING_PROFILES_ACTIVE docker
+ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz dockerize.tar.gz
+RUN tar xzf dockerize.tar.gz
+RUN chmod +x dockerize
+ADD ./target/*.jar /app.jar
+EXPOSE ${EXPOSED_PORT}
+ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
+
diff --git a/test-local-deployment.sh b/test-local-deployment.sh
new file mode 100644
index 0000000000..56b0279f33
--- /dev/null
+++ b/test-local-deployment.sh
@@ -0,0 +1,2 @@
+# test-local-deployment
+docker-compose -f docker-compose-local.yml up
\ No newline at end of file