github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/deploy/dev/docker/deploy_docker.sh (about) 1 #!/bin/bash 2 3 set -e 4 5 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 name=$(basename "$0") 7 8 usage() { 9 echo "Usage: $name [-c=NUM] [-d=NUM] [-f=LIST] [-g] [-h] [-l] [-m] [-p=NUM] [-s] [-t=NUM] [-qs=AWS_DIR (Optional)]" 10 echo " -c=NUM or --cluster=NUM : where NUM is the number of clusters" 11 echo " -d=NUM or --directories=NUM : where NUM is the number of local cache directories" 12 echo " -f=LIST or --filesystems=LIST : where LIST is a comma separated list of filesystems" 13 echo " -h or --help : show usage" 14 echo " -l or --last : redeploy using the arguments from the last ais docker deployment" 15 echo " -m or --multi : use multiple networks" 16 echo " -p=NUM or --proxy=NUM : where NUM is the number of proxies" 17 echo " -s or --single : use a single network" 18 echo " -t=NUM or --target=NUM : where NUM is the number of targets" 19 echo " -qs=AWS_DIR or --quickstart=AWS_DIR : deploys a quickstart version of AIS with one proxy, one targe and one local file system" 20 echo " -nocloud : to deploy AIS without any 3rd party backend provider" 21 echo " -grafana : starts Graphite and Grafana containers" 22 echo " -nodiskio=BOOL : run Dry-Run mode with disk IO is disabled (default = false)" 23 echo " -dryobjsize=SIZE : size of an object when a source is a 'fake' one." 24 echo " 'g' or 'G' - GiB, 'm' or 'M' - MiB, 'k' or 'K' - KiB. Default value is '8m'" 25 echo "Note:" 26 echo " -if the -f or --filesystems flag is used, the -d or --directories flag is disabled and vice-versa" 27 echo " -if the -a or --aws flag is used, the -g or --gcp flag is disabled and vice-versa" 28 echo " -if both -f and -d or -a and -g are provided, the flag that is provided last will take precedence" 29 echo " -if the -s or --single and -m or --multi flag are used, then multiple networks will take precedence" 30 echo 31 exit 1; 32 } 33 34 is_number() { 35 if ! [[ "$1" =~ ^[0-9]+$ ]] ; then 36 echo "Error: '$1' is not a number"; exit 1 37 fi 38 } 39 40 is_size() { 41 if [ -z "$1" ]; then 42 DRYOBJSIZE="8m" 43 elif ! [[ "$1" =~ ^[0-9]+[g|G|m|M|k|K]$ ]] ; then 44 echo "Error: '$1' is not a valid size"; exit 1 45 fi 46 } 47 48 save_env() { 49 echo "Public network: ${PUB_SUBNET}" 50 echo "Internal control network: ${INT_CONTROL_SUBNET}" 51 echo "Internal data network: ${INT_DATA_SUBNET}" 52 export PUB_SUBNET=${PUB_SUBNET} 53 export INT_CONTROL_SUBNET=${INT_CONTROL_SUBNET} 54 export INT_DATA_SUBNET=${INT_DATA_SUBNET} 55 56 echo "" > ${TMP_ENV} 57 echo "QUICK=${QUICK}" >> ${TMP_ENV} 58 echo "TARGET_CNT=${TARGET_CNT:-1000}" >> ${TMP_ENV} 59 echo "AIS_BACKEND_PROVIDERS=${AIS_BACKEND_PROVIDERS-}" >> ${TMP_ENV} 60 echo "TEST_FSPATH_COUNT=${TEST_FSPATH_COUNT}" >> ${TMP_ENV} 61 echo "AIS_FS_PATHS=${AIS_FS_PATHS}" >> ${TMP_ENV} 62 63 echo "NODISKIO=${NODISKIO-false}" >> ${TMP_ENV} 64 echo "DRYOBJSIZE=${DRYOBJSIZE-8m}" >> ${TMP_ENV} 65 66 echo "GRAPHITE_PORT=${GRAPHITE_PORT}" >> ${TMP_ENV} 67 echo "GRAPHITE_SERVER=${GRAPHITE_SERVER}" >> ${TMP_ENV} 68 69 echo "PUB_SUBNET=${PUB_SUBNET}" >> ${TMP_ENV} 70 echo "INT_CONTROL_SUBNET=${INT_CONTROL_SUBNET}" >> ${TMP_ENV} 71 echo "INT_DATA_SUBNET=${INT_DATA_SUBNET}" >> ${TMP_ENV} 72 echo "HOSTNAME_LIST=${HOSTNAME_LIST}" >> ${TMP_ENV} 73 echo "HOSTNAME_LIST_INTRA_CONTROL=${HOSTNAME_LIST_INTRA_CONTROL}" >> ${TMP_ENV} 74 echo "HOSTNAME_LIST_INTRA_DATA=${HOSTNAME_LIST_INTRA_DATA}" >> ${TMP_ENV} 75 } 76 77 save_setup() { 78 echo "" > ${SETUP_FILE} 79 echo "Saving setup" 80 echo "CLUSTER_CNT=$CLUSTER_CNT" >> ${SETUP_FILE} 81 echo "PROXY_CNT=$PROXY_CNT" >> ${SETUP_FILE} 82 echo "TARGET_CNT=$TARGET_CNT" >> ${SETUP_FILE} 83 echo "NETWORK=${NETWORK}" >> ${SETUP_FILE} 84 85 echo "AIS_BACKEND_PROVIDERS=$AIS_BACKEND_PROVIDERS" >> ${SETUP_FILE} 86 87 echo "DRYRUN"=$DRYRUN >> ${SETUP_FILE} 88 echo "NODISKIO"=$NODISKIO >> ${SETUP_FILE} 89 echo "DRYOBJSIZE"=$DRYOBJSIZE >> ${SETUP_FILE} 90 91 echo "FS_LIST=$FS_LIST" >> ${SETUP_FILE} 92 echo "TEST_FSPATH_COUNT=${TEST_FSPATH_COUNT}" >> ${SETUP_FILE} 93 echo "AIS_FS_PATHS=$AIS_FS_PATHS" >> ${SETUP_FILE} 94 95 echo "PRIMARY_HOST_IP=${PRIMARY_HOST_IP}" >> ${SETUP_FILE} 96 echo "NEXT_TIER_HOST_IP=${NEXT_TIER_HOST_IP}" >> ${SETUP_FILE} 97 98 echo "PORT=$PORT" >> ${SETUP_FILE} 99 echo "PORT_INTRA_CONTROL=$PORT_INTRA_CONTROL" >> ${SETUP_FILE} 100 echo "PORT_INTRA_DATA=$PORT_INTRA_DATA" >> ${SETUP_FILE} 101 echo "Finished saving setup" 102 } 103 104 get_setup() { 105 if [ -f $"${SETUP_FILE}" ]; then 106 source ${SETUP_FILE} 107 else 108 echo "No setup configuration found for your last docker deployment. Exiting..." 109 exit 1 110 fi 111 } 112 113 deploy_mode() { 114 if $NODISKIO; then 115 echo "Deployed in no disk IO mode with ${DRYOBJSIZE} fake object size." 116 else 117 echo "Deployed in normal mode." 118 fi 119 } 120 121 deploy_quickstart() { 122 cp $DIR/../local/aisnode_config.sh aisnode_config.sh 123 cp $DIR/../../conf/limits.conf limits.conf 124 125 QS_AWSDIR=${1:-'~/.aws/'} 126 QS_AWSDIR="${QS_AWSDIR/#\~/$HOME}" 127 if docker ps | grep ais-quickstart > /dev/null 2>&1; then 128 echo "Terminating old instance of quickstart cluster ..." 129 ./stop_docker.sh -qs 130 fi 131 echo "Building Docker image ..." 132 docker build -q -t ais-quickstart --build-arg GOBASE=/go --build-arg QUICK=quick . 133 if [ ! -d "$QS_AWSDIR" ]; then 134 echo "AWS credentials not found (tests may not work!) ..." 135 docker run -di --entrypoint=/bin/bash ais-quickstart:latest 136 else 137 echo "AWS credentials found (${QS_AWSDIR}), continuing ..." 138 docker run -di --entrypoint=/bin/bash -v ${QS_AWSDIR}credentials:/root/.aws/credentials -v ${QS_AWSDIR}config:/root/.aws/config ais-quickstart:latest 139 fi 140 141 echo "SSH into container ..." 142 container_id=$(docker ps | grep ais-quickstart | awk '{ print $1 }') 143 docker exec -it $container_id /bin/bash -c "echo 'Hello from AIS!'; /bin/bash;" 144 145 rm -rf aisnode_config.sh 146 rm -rf limits.conf 147 } 148 149 150 if ! [ -x "$(command -v docker-compose)" ]; then 151 echo 'Error: docker-compose is not installed.' >&2 152 exit 1 153 fi 154 155 AIS_BACKEND_PROVIDERS="" 156 CLUSTER_CNT=0 157 PROXY_CNT=0 158 TARGET_CNT=0 159 FS_LIST="" 160 TEST_FSPATH_COUNT=1 161 NETWORK="" 162 AWS_ENV="" 163 164 mkdir -p /tmp/docker_ais 165 LOCAL_AWS="/tmp/docker_ais/aws.env" 166 SETUP_FILE="/tmp/docker_ais/deploy.env" 167 TMP_ENV="/tmp/docker_ais/tmp.env" 168 touch ${TMP_ENV} 169 170 GRAFANA=false 171 172 # Indicate which dry-run mode the cluster is running on 173 DRYRUN=0 174 NODISKIO=false 175 DRYOBJSIZE="8m" 176 177 source ../utils.sh 178 179 for i in "$@" 180 do 181 case $i in 182 -c=*|--cluster=*) 183 CLUSTER_CNT="${i#*=}" 184 is_number $CLUSTER_CNT 185 NETWORK="multi" 186 shift # past argument=value 187 ;; 188 189 -d=*|--directories=*) 190 TEST_FSPATH_COUNT="${i#*=}" 191 is_number $TEST_FSPATH_COUNT 192 FS_LIST="" 193 shift # past argument=value 194 ;; 195 196 -f=*|--filesystems=*) 197 FS_LIST="${i#*=}" 198 TEST_FSPATH_COUNT=0 199 shift # past argument=value 200 ;; 201 202 -h|--help) 203 usage 204 shift # past argument 205 ;; 206 207 -l|--last) 208 get_setup 209 break 210 shift # past argument 211 ;; 212 213 -m|--multi) 214 NETWORK="multi" 215 shift # past argument 216 ;; 217 218 -p=*|--proxy=*) 219 PROXY_CNT="${i#*=}" 220 is_number $PROXY_CNT 221 shift # past argument=value 222 ;; 223 224 -qs=*|--quickstart=*|-qs|--quickstart) 225 deploy_quickstart "${i#*=}" 226 exit 1 227 ;; 228 229 -s|--single) 230 if [ "${NETWORK}" != "multi" ]; then 231 NETWORK="single" 232 fi 233 shift # past argument=value 234 ;; 235 236 -t=*|--target=*) 237 TARGET_CNT="${i#*=}" 238 is_number $TARGET_CNT 239 shift # past argument=value 240 ;; 241 242 -grafana) 243 GRAFANA=true 244 shift # past argument 245 ;; 246 247 -nodiskio=*|--nodiskio=*) 248 export NODISKIO="${i#*=}" 249 if $NODISKIO; then 250 DRYRUN=1 251 fi 252 shift # past argument=value 253 ;; 254 255 -dryobjsize=*|--dryobjsize=*) 256 DRYOBJSIZE="${i#*=}" 257 is_size $DRYOBJSIZE 258 shift # past argument=value 259 ;; 260 261 *) 262 usage 263 ;; 264 esac 265 done 266 267 268 if [ $DRYRUN -ne 0 ]; then 269 echo "Configure Dry Run object size (default is '8m' - 8 megabytes):" 270 echo "Note: 'g' or 'G' - GiB, 'm' or 'M' - MiB, 'k' or 'K' - KiB" 271 echo "No input will result in using the default size" 272 read DRYOBJSIZE 273 is_size $DRYOBJSIZE 274 fi 275 276 parse_backend_providers 277 278 touch $LOCAL_AWS 279 echo "Configured backend providers: '${AIS_BACKEND_PROVIDERS}'" 280 if [[ "${AIS_BACKEND_PROVIDERS}" == *aws* ]]; then 281 echo "Enter the location of your AWS configuration and credentials files:" 282 echo "Note: No input will result in using the default aws dir (~/.aws/)" 283 read AWS_ENV 284 285 if [[ -z ${aws_env} ]]; then 286 AWS_ENV="${HOME}/.aws/" 287 fi 288 289 AWS_ENV="${AWS_ENV/#\~/$HOME}" 290 temp_file="${AWS_ENV}/credentials" 291 has_reg=0 292 if [[ -f ${temp_file} ]]; then 293 cp ${temp_file} ${LOCAL_AWS} 294 has_reg=$(cat ${temp_file} | grep -c "region") 295 else 296 echo "No AWS credentials file found in specified directory. Exiting..." 297 exit 1 298 fi 299 300 if [[ $has_reg -eq 0 ]]; then 301 temp_file="${AWS_ENV}/config" 302 if [[ -f ${temp_file} ]] && [[ $(cat ${temp_file} | grep -c "region") -gt 0 ]]; then 303 grep region ${temp_file} >> ${LOCAL_AWS} 304 else 305 echo "No region config field found in aws directory. Exiting..." 306 exit 1 307 fi 308 fi 309 310 sed -i 's/\[default\]//g' ${LOCAL_AWS} 311 sed -i 's/ = /=/g' ${LOCAL_AWS} 312 sed -i 's/aws_access_key_id/AWS_ACCESS_KEY_ID/g' ${LOCAL_AWS} 313 sed -i 's/aws_secret_access_key/AWS_SECRET_ACCESS_KEY/g' ${LOCAL_AWS} 314 sed -i 's/region/AWS_REGION/g' ${LOCAL_AWS} 315 fi 316 317 if [ "$CLUSTER_CNT" -eq 0 ]; then 318 echo Enter number of AIStore clusters: 319 read CLUSTER_CNT 320 is_number $CLUSTER_CNT 321 if [ "$CLUSTER_CNT" -gt 1 ]; then 322 NETWORK="multi" 323 fi 324 fi 325 326 if [[ -z "${NETWORK// }" ]]; then 327 echo "Enter 's' for single network configuration or 'm' for multi-network configuration:" 328 read network_config 329 if [ "$network_config" = "s" ]; then 330 NETWORK="single" 331 elif [ $network_config = 'm' ] ; then 332 NETWORK="multi" 333 else 334 echo Valid network configuration was not supplied. 335 usage 336 fi 337 fi 338 339 if [ "$TARGET_CNT" -eq 0 ]; then 340 echo Enter number of target servers: 341 read TARGET_CNT 342 is_number $TARGET_CNT 343 fi 344 345 if [ "$PROXY_CNT" -eq 0 ]; then 346 echo Enter number of proxy servers: 347 read PROXY_CNT 348 is_number $PROXY_CNT 349 if [ $PROXY_CNT -lt 1 ] ; then 350 echo "Error: $PROXY_CNT is less than 1"; exit 1 351 fi 352 fi 353 354 AIS_FS_PATHS="" 355 if [ "$FS_LIST" = "" ] && [ "$TEST_FSPATH_COUNT" -eq 0 ]; then 356 echo Select 357 echo 1: Local cache directories 358 echo 2: Filesystems 359 echo "Enter your cache choice (1 or 2):" 360 read cachesource 361 is_number $cachesource 362 if [ $cachesource -eq 1 ]; then 363 echo Enter number of local cache directories: 364 read TEST_FSPATH_COUNT 365 is_number $TEST_FSPATH_COUNT 366 elif [ $cachesource -eq 2 ]; then 367 echo Enter filesystem info in comma separated format ex: /tmp/ais1,/tmp/ais: 368 read FS_LIST 369 else 370 echo "Not a valid entry. Exiting..." 371 exit 1 372 fi 373 fi 374 375 if [ "$FS_LIST" != "" ] && [ "$TEST_FSPATH_COUNT" -eq 0 ]; then 376 AIS_FS_PATHS="" 377 IFS=',' read -r -a array <<< "$FS_LIST" 378 for element in "${array[@]}" 379 do 380 AIS_FS_PATHS="$AIS_FS_PATHS,\"$element\" : {} " 381 done 382 AIS_FS_PATHS=${AIS_FS_PATHS#","} 383 fi 384 385 composer_file="${DIR}/docker-compose.singlenet.yml" 386 if [ "${NETWORK}" = "multi" ]; then 387 composer_file="${DIR}/docker-compose.singlenet.yml -f ${DIR}/docker-compose.multinet.yml" 388 fi 389 390 cp $DIR/../local/aisnode_config.sh aisnode_config.sh 391 cp $DIR/../../conf/limits.conf limits.conf 392 393 docker network create docker_default || true 394 if [ "$GRAFANA" == true ]; then 395 GRAPHITE_PORT=2003 396 GRAPHITE_SERVER="graphite" 397 docker-compose -f ${composer_file} up --build -d graphite 398 docker-compose -f ${composer_file} up --build -d grafana 399 else 400 GRAPHITE_PORT=2003 401 GRAPHITE_SERVER="localhost" 402 fi 403 404 PORT_INTRA_CONTROL=9080 405 PORT_INTRA_DATA=10080 406 export PORT=51080 407 export AIS_NO_DISK_IO=${NODISKIO} 408 export AIS_BACKEND_PROVIDERS=${AIS_BACKEND_PROVIDERS} 409 # Setting the IP addresses for the containers 410 echo "Network type: ${NETWORK}" 411 for ((i=0; i<${CLUSTER_CNT}; i++)); do 412 PUB_NET="172.5$((0 + (i * 3))).0" 413 PUB_SUBNET="${PUB_NET}.0/24" 414 INT_CONTROL_NET="172.5$((1 + (i * 3))).0" 415 INT_CONTROL_SUBNET="${INT_CONTROL_NET}.0/24" 416 INT_DATA_NET="172.5$((2 + (i * 3))).0" 417 INT_DATA_SUBNET="${INT_DATA_NET}.0/24" 418 419 if [ $i -eq 0 ]; then 420 PRIMARY_HOST_IP="${PUB_NET}.2" 421 fi 422 if [ $i -eq 1 ]; then 423 NEXT_TIER_HOST_IP="${PUB_NET}.2" 424 fi 425 426 HOSTNAME_LIST="" 427 HOSTNAME_LIST_INTRA_CONTROL="" 428 HOSTNAME_LIST_INTRA_DATA="" 429 430 mkdir -p /tmp/ais/${i} 431 # UID is used to ensure that volumes' folders have the same permissions as 432 # the user who starts the script. Otherwise they would have `root` permission. 433 export UID # (see docker compose files) 434 export CLUSTER=${i} 435 436 for j in $(seq 2 $(((TARGET_CNT + PROXY_CNT + 1) * CLUSTER_CNT))); do 437 HOSTNAME_LIST="${HOSTNAME_LIST}${PUB_NET}.$j," 438 done 439 if [ "$HOSTNAME_LIST" != "" ]; then 440 HOSTNAME_LIST=${HOSTNAME_LIST/%?/} # remove last "," 441 fi 442 443 if [ "${NETWORK}" = "multi" ]; then 444 # HOSTNAME_LIST_INTRA 445 for j in $(seq 2 $(((TARGET_CNT + PROXY_CNT + 1) * CLUSTER_CNT))); do 446 HOSTNAME_LIST_INTRA_CONTROL="${HOSTNAME_LIST_INTRA_CONTROL}${INT_CONTROL_NET}.$j," 447 done 448 HOSTNAME_LIST_INTRA_CONTROL=${HOSTNAME_LIST_INTRA_CONTROL/%?/} # remove last "," 449 450 # HOSTNAME_LIST_INTRA_DATA 451 for j in $(seq 2 $(((TARGET_CNT + PROXY_CNT + 1) * CLUSTER_CNT))); do 452 HOSTNAME_LIST_INTRA_DATA="${HOSTNAME_LIST_INTRA_DATA}${INT_DATA_NET}.$j," 453 done 454 HOSTNAME_LIST_INTRA_DATA=${HOSTNAME_LIST_INTRA_DATA/%?/} # remove last "," 455 fi 456 457 save_env 458 459 echo Stopping running clusters... 460 docker-compose -p ais${i} -f ${composer_file} down 461 462 echo Building Image.. 463 docker-compose -p ais${i} -f ${composer_file} build 464 465 echo Starting Primary Proxy 466 docker-compose -p ais${i} -f ${composer_file} up -d proxy 467 sleep 2 # give primary proxy some room to breathe 468 echo Starting cluster .. 469 PRIMARY_IP=$(docker inspect -f "{{ .NetworkSettings.Networks.ais${i}_public.IPAddress }}" ais${i}_proxy_1) 470 PRIMARY_IP=${PRIMARY_IP} docker-compose -p ais${i} -f ${composer_file} up -d --scale proxy=${PROXY_CNT} --scale target=$TARGET_CNT --scale grafana=0 --scale graphite=0 --no-recreate 471 done 472 473 sleep 5 474 # Records all environment variables into ${SETUP_FILE} 475 save_setup 476 477 if [ "$CLUSTER_CNT" -gt 1 ] && [ "${NETWORK}" = "multi" ]; then 478 echo Connecting clusters together... 479 for container_name in $(docker ps --format "{{.Names}}"); do 480 container_id=$(docker ps -aqf "name=${container_name}") 481 for ((i=0; i<${CLUSTER_CNT}; i++)); do 482 if [[ $container_name != ais${i}_* ]]; then 483 echo Connecting $container_name to $ais${i}_public 484 docker network connect ais${i}_public $container_id 485 if [[ $container_name == *"_target_"* ]]; then 486 echo Connecting $container_name to $ais${i}_internal_data 487 docker network connect ais${i}_internal_data $container_id 488 fi 489 fi 490 done 491 done 492 fi 493 494 if [ "$GRAFANA" == true ]; then 495 # Set up Graphite datasource 496 curl -d '{"name":"Graphite","type":"graphite","url":"http://graphite:80","access":"proxy","basicAuth":false,"isDefault":true}' -H "Content-Type: application/json" -X POST http://admin:admin@localhost:3000/api/datasources > /dev/null 2>&1 497 fi 498 499 # Consider moving these to a folder instead of deleting - for future reference 500 rm aisnode_config.sh 501 rm limits.conf 502 docker ps 503 504 # Install the CLI 505 cd $DIR/../../../ && make cli 506 507 deploy_mode 508 509 for ((i=0; i<${CLUSTER_CNT}; i++)); do 510 PRIMARY_IP=$(docker inspect -f "{{ .NetworkSettings.Networks.ais${i}_public.IPAddress }}" ais${i}_proxy_1) 511 echo "Cluster${i} deployed! use 'AIS_ENDPOINT=\"http://${PRIMARY_IP}:${PORT}\" ais show cluster' to view cluster info" 512 done 513 514 echo done