Skript prod_deploy.sh

Automaticky generovaná dokumentace skriptu scripts/prod_deploy.sh.

  1#!/bin/bash
  2###########
  3#### SCRIPT: DEPLOYMENT from DOCKERHUB into SWARM
  4#### PARAMS: see -h
  5###########
  6#USAGE: deployment based on release on GITHUB, i.e. GitHub actions published docker images on Docker Hub
  7
  8# ------ !!!! ----------
  9SKIP_ALL_CHECKS=1 #IF CHANGED TO 1 then all MANUAL CHECKS, ie questions during script runtime are disabled!
 10# ------ !!!! ----------
 11
 12ask_continue () {
 13    while true; do
 14        
 15        read -p "$1 (y or n): " input        
 16        case $input in
 17            [yY]*)
 18                echo '---Continuing!'
 19                break
 20                ;;
 21            [nN]*)
 22                echo '***So do THAT, exiting!'
 23                exit 1
 24                ;;
 25             *)
 26                echo '***Invalid input' >&2
 27        esac
 28    done
 29}
 30
 31echo_dec ()
 32{
 33    echo "---------------------------------------"
 34    echo "--> $1"
 35    echo "---------------------------------------"
 36}
 37
 38er () {
 39    echo_dec "${1}"
 40    eval "${1}"
 41    ret_val=$?
 42    echo "....................."
 43    echo ">> DONE: ${1} with status: ${ret_val}"
 44    return $ret_val
 45}
 46
 47check_create_network () {
 48    
 49    docker network inspect ${network_name} > /dev/null 2>&1
 50    network_status=$?
 51    if [ ${network_status} -eq 1  ]; then
 52      er "docker network create -d overlay --attachable ${network_name}"
 53      echo_dec "Network ${network_name} created"
 54    else
 55       echo_dec "Network ${network_name} already exists"
 56    fi
 57}
 58
 59check_stack_exists ()
 60{
 61    docker stack ps ${stack_name} > /dev/null 2>&1
 62    stack_status=$?
 63    return ${stack_status}
 64}
 65
 66run_default ()
 67{
 68   echo_dec "# DEPLOYMENT in SWARM MODE (i.e. host has to be joined or initiated as SWARM NODE) @${start_time}"
 69
 70   #CHECK SWARM ACTIVATED
 71   docker node ls
 72   status_swarm=$?
 73
 74   if [ $status_swarm -ne 0 ]; then
 75        echo_dec "SWARM not initiated or joined at this HOST. Exiting"
 76        exit 1
 77   fi
 78   in_args="${1}"
 79   
 80   #DISCLAIMER about DEFAULT CASE triggering
 81   if [ ${SKIP_ALL_CHECKS} -eq 0 ] && [ "${in_args}" == "" ]; then
 82    ask_continue "Do you want to continue with DEFAULT CASE? "
 83   fi
 84   echo_dec "DEPLOY  all services."
 85   
 86   #RAISE questions about conditions for deployemnt
 87   do_manual_checks
 88
 89   # Check network exists
 90   check_create_network
 91
 92   #Update images
 93   er "${cmd_pull_images}"
 94   if [ $? -gt 0 ]; then
 95	echo_dec "${msg_pull_fail} with TAG: ${IMAGE_TAG} => EXITING"
 96	exit
 97   fi
 98
 99      er "${cmd_deploy_base} ${compose_proxy} ${stack_name} && \
100      ${cmd_deploy_base} ${compose_prod} ${stack_name}" && \
101      echo_dec "$msg_success" || echo_dec "${msg_fail_build}"
102}
103
104Help ()
105{
106    cat <<EOF
107    !!!MUST BE RUN from REPOSIOTRY root like =>
108    usage: ./scrips/${script_name} [-x|-u <tag_name>|-t <tag_name>|-i], 
109    ---
110       PURPOSE: manage deployment/run of production docker images build from GIT repository for AIS CR project in SWARM mode
111    ----
112
113    Examples on options:
114    1) Remove complete docker stack, i.e all services
115    
116         $./scripts/${script_name} -x  
117    
118    2) Update all services with new images
119       
120       $./scripts/${script_name} -u <tag_name>
121
122    3) Deploy or redeploy all services in swarm mode with image tag (version number or "latest")
123       
124       $./scripts/${script_name} -t <tag_name>
125
126    4) Get information about available versions.
127
128       $./scripts/${script_name} -i
129
130    -----
131    Summnary:
132    -h help
133    -x remove docker stack (all services)
134    -u update all services using rolling approach with tag name <tag_name>
135    -t deploy all services in swarm mode with tag name <tag_name>
136    -i information about available versions
137
138EOF
139}
140
141do_manual_checks ()
142{
143    # DO SOME MANUAL CHECKS of deployment steps by ASKING questions (can be skipped by providing arbitrary command-line argument to the script)
144    if [ ${SKIP_ALL_CHECKS} -eq 1 ]; then
145        echo_dec "DEPLOYMENT QUESTIONS SKIPPED due to CONSTANT SKIP_ALL_CHECKS set ${SKIP_ALL_CHECKS}"
146    else
147        # DO SOME MANUAL CHECKS of deployment steps by ASKING questions (can be skipped)
148        ask_continue "1.Did you APPLY MANUAL migrations to DB (if relevant)?"
149        ask_continue "2.Did you MAKE release on GitHUB and waited to for end Github Action for publishing Docker images ?"
150        ask_continue "3.Did you CONFIGURE secrets to point to desired DB location (using docker secrets db_conf, i.e swarm secrets MUST be already existing) ?"
151    fi
152}
153
154script_name=$(basename ${0})
155passed_args="$@"
156
157# Read first positional argument if exists (before any flags like -t or -u) 
158if [[ "$1" != -* ]] && [[ -n "$1" ]]; then
159    IMAGE_SOURCE=$(echo "$1" | tr '[:upper:]' '[:lower:]')
160    if [[ "$IMAGE_SOURCE" != "dockerhub" && "$IMAGE_SOURCE" != "github" ]]; then
161        echo "ERROR: Invalid source type '$IMAGE_SOURCE'. Use 'dockerhub' or 'github'."
162        exit 1
163    fi
164    echo ">>> IMAGE SOURCE: ${IMAGE_SOURCE}"
165    shift # Shift to process remaining args with getopts
166fi
167
168IMAGE_SOURCE="${IMAGE_SOURCE:-github}" # Default to github if not specified
169
170while getopts ":t:u:" option; do
171    
172   case ${option} in
173        t|u|d)  #Overriding of default latest image by providing specific tag
174            if [ "$OPTARG" == "latest" ]; then
175                echo "Warning: IMAGE TAG must not be 'latest'"
176                exit 1
177            fi
178            export IMAGE_TAG="${OPTARG}"
179            tag_passed="yes"
180            echo "IMAGE TAG FOR DOCKER IMAGES IS >>>> ${IMAGE_TAG}"
181            ;;
182	 *)
183            ;;
184    esac
185done
186
187#INPUTS
188
189# Override image source path based on the chosen source
190# Compose image tags (must match how GitHub Actions publish images)
191case $IMAGE_SOURCE in
192  dockerhub)
193    export amcr_image="aiscr/webamcr:${IMAGE_TAG}"
194    export proxy_image="aiscr/webamcr-proxy:${IMAGE_TAG}"
195    export redis_image="aiscr/webamcr-redis:${IMAGE_TAG}"
196    ;;
197  github)
198    export amcr_image="ghcr.io/arup-cas/aiscr-webamcr:${IMAGE_TAG}"
199    export proxy_image="ghcr.io/arup-cas/aiscr-webamcr-proxy:${IMAGE_TAG}"
200    export redis_image="ghcr.io/arup-cas/aiscr-webamcr-redis:${IMAGE_TAG}"
201    ;;
202esac
203
204stack_name="swarm_webamcr"
205network_name="prod-net" #MUST MATCH WITH COMPOSE FILES!!!
206
207compose_proxy="docker-compose-proxy.yml"
208compose_prod="docker-compose.yml"
209
210msg_fail_build="!! DEPLOYMENT not successfull"
211msg_pull_fail="!! PULL not successfull"
212msg_pull_success="PULL success"
213msg_success="DEPLOYED in SWARM MODE ---> APPLICATION ACCESSIBLE on: port 8080"
214
215#TRANSLATION backups path
216tr_path="$HOME/translations_backup"
217mkdir -p ${tr_path}
218
219#LOGGING
220log_dir="logs/prod_deploy"
221start_time=$(date +%Y%m%dT%H%M%S)
222log_file="${start_time}_prod-deployment_${passed_args}.log"
223mkdir -p ${log_dir}
224
225OPTIND=1
226
227#REDIRECT to log
228exec > >(tee "${log_dir}/${log_file}" )
229exec 2>&1
230
231#Build commands
232cmd_stack_rm="docker stack rm ${stack_name}"
233cmd_pull_images="docker pull ${proxy_image} && docker pull ${amcr_image}"
234cmd_deploy_base="docker stack deploy --compose-file"
235
236prune_images (){
237#Cleaning old images
238echo "Pruning unused Docker images..."
239docker image prune -f
240}
241
242option_passed=false
243
244while getopts "hxu:t:i" option; do
245   case ${option} in
246      h) # display Help
247         echo "OPTION: -h"
248         option_passed=true
249         Help
250         exit;;
251      x) echo "OPTION: -x" 
252         option_passed=true
253         prune_images
254         echo_dec "Remove docker stack: ${stack_name}"
255         if check_stack_exists; then
256            er "${cmd_stack_rm}" && \
257            echo_dec "Stack ${stack_name} removal successful" || echo_dec "Stack ${stack_name} removal FAILED"
258         else
259             echo_dec "STACK ${stack_name} doesn't exist so can't be removed!!!"
260        fi
261        echo sleep 20 second to wait before network is really removed.
262        sleep 20 # Need to wait before network is really removed.
263         ;;
264      u) #update services
265        echo "OPTION: -u with ${IMAGE_TAG}"
266        option_passed=true
267        prune_images
268        echo_dec "Update services with new images!"
269        if check_stack_exists ; then
270            do_manual_checks
271            docker service update --force --image ${amcr_image} ${stack_name}_web && \
272            docker service update --force --image ${proxy_image} ${stack_name}_proxy && \
273            echo_dec "$msg_success" || echo_dec "$msg_fail_build"
274        else
275            echo_dec "SERVICE CANNOT BE UPDATED because stack doesn't exist !!!"
276        fi
277        ;;
278      t)
279        echo "OPTION: -t with ${IMAGE_TAG}"
280        option_passed=true
281        prune_images
282        run_default b
283	      ;;
284      i)
285        option_passed=true
286        echo 10 last available versions
287        curl -s https://hub.docker.com/v2/repositories/aiscr/webamcr/tags/ | jq '."results"[0:10] | .[]["name"]'
288	      ;;
289     \?) # Invalid option
290         echo_dec "OPTION: INVALID"
291         echo "Error: Invalid option ${option}"
292         exit;;
293   esac
294done
295
296if [ "$option_passed" = false ]; then
297   echo_dec "No option is passed as ARG, you have to specify a parameter, for help use -h."
298fi
299
300exit 0