Blue-Green Deployment ntawm cov nyiaj ua haujlwm yam tsawg kawg nkaus

Hauv tsab xov xwm no peb yuav siv bash, SSH, docker и nginx Peb npaj ib qho kev xa tawm daim ntawv thov web uas tsis muaj teeb meem. Kev xa tawm xiav-ntsuab yog ib txoj kev uas tso cai rau kev hloov kho daim ntawv thov tam sim ntawd yam tsis tau tsis lees txais cov lus thov. Nws yog ib qho ntawm cov tswv yim xa tawm xoom-downtime thiab zoo tshaj plaws rau cov ntawv thov nrog ib qho piv txwv tab sis muaj peev xwm khau raj qhov thib ob, npaj siv tau nyob ze.

Cia peb hais tias koj muaj ib daim ntawv thov web uas ntau tus neeg siv khoom siv tas li, thiab nws yeej tsis muaj peev xwm zaum ob peb feeb xwb. Koj yeej xav tau xa tawm qhov hloov tshiab ntawm lub tsev qiv ntawv, kho qhov kab laum, lossis ib qho tshiab zoo nkauj. Feem ntau, koj yuav tsum nres daim ntawv thov, hloov nws, thiab tom qab ntawd rov pib dua. Nrog Docker, koj tuaj yeem hloov nws ua ntej, tom qab ntawd rov pib dua, tab sis tseem yuav muaj ib lub sijhawm uas cov lus thov rau daim ntawv thov yuav tsis raug ua tiav, vim tias cov ntawv thov feem ntau xav tau qee lub sijhawm los thauj khoom thawj zaug. Yuav ua li cas yog tias nws pib tab sis ua tsis tiav? Qhov ntawd yog qhov teeb meem; cia peb daws nws nrog cov peev txheej tsawg kawg nkaus thiab zoo nkauj li sai tau.

LUS CEEV: Feem ntau ntawm tsab xov xwm no yog nthuav tawm hauv hom ntawv sim - ua ib qho kev kaw suab hauv console. Kuv vam tias nws tsis nyuaj dhau rau kev nkag siab, thiab cov lej tau sau cia txaus. Rau qhov kev xav ntawm huab cua, xav txog cov no tsis yog cov lej snippets xwb, tab sis daim ntawv los ntawm lub xov tooj kho vajtse.

Blue-Green Deployment ntawm cov nyiaj ua haujlwm yam tsawg kawg nkaus

Cov txheej txheem nthuav uas nyuaj nrhiav los ntawm kev nyeem cov lej tau piav qhia nyob rau thaum pib ntawm txhua ntu. Yog tias muaj qee yam tsis meej, Google nws thiab tshawb xyuas nws. piav qhia (Ua tsaug, nws rov ua haujlwm dua, ua tsaug rau Telegram raug tshem tawm.) Yog tias koj nrhiav tsis tau dab tsi hauv Google, nug hauv cov lus. Kuv zoo siab ntxiv rau ntu "Cov Txuj Ci Nthuav".

Cia peb pib.

$ mkdir blue-green-deployment && cd $_

kev pab cuam

Cia peb tsim ib qho kev pabcuam sim thiab muab tso rau hauv ib lub thawv.

Cov txheej txheem nthuav

  • cat << EOF > file-name (Nov Daim Ntawv + Kev Hloov Chaw I/O) yog ib txoj hauv kev los tsim cov ntaub ntawv ntau kab nrog ib lo lus txib. Txhua yam uas bash yuav nyeem los ntawm /dev/stdin tom qab kab no thiab ua ntej kab EOF yuav raug sau tseg rau hauv file-name.
  • wget -qO- URL (piav qhia) - tso tawm cov ntaub ntawv tau txais los ntawm HTTP rau /dev/stdout (analog curl URL).

Luam Tawm

Kuv txhob txwm ua kom daim snippet no tawg kom Python highlighting ua haujlwm tau. Yuav muaj lwm ntu zoo li no thaum kawg. Xav txog cov ntu no ua daim ntawv uas raug txiav rau kev xa mus rau lub chaw ua haujlwm highlighting (qhov twg cov lej tau pleev xim nrog cov highlighters), thiab tom qab ntawd cov ntu no raug muab tso rov qab rau hauv.

$ cat << EOF > uptimer.py
from http.server import BaseHTTPRequestHandler, HTTPServer
from time import monotonic

app_version = 1
app_name = f'Uptimer v{app_version}.0'
loading_seconds = 15 - app_version * 5

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            try:
                t = monotonic() - server_start
                if t < loading_seconds:
                    self.send_error(503)
                else:
                    self.send_response(200)
                    self.send_header('Content-Type', 'text/html')
                    self.end_headers()
                    response = f'<h2>{app_name} is running for {t:3.1f} seconds.</h2>n'
                    self.wfile.write(response.encode('utf-8'))
            except Exception:
                self.send_error(500)
        else:
            self.send_error(404)

httpd = HTTPServer(('', 8080), Handler)
server_start = monotonic()
print(f'{app_name} (loads in {loading_seconds} sec.) started.')
httpd.serve_forever()
EOF

$ cat << EOF > Dockerfile
FROM python:alpine
EXPOSE 8080
COPY uptimer.py app.py
CMD [ "python", "-u", "./app.py" ]
EOF

$ docker build --tag uptimer .
Sending build context to Docker daemon  39.42kB
Step 1/4 : FROM python:alpine
 ---> 8ecf5a48c789
Step 2/4 : EXPOSE 8080
 ---> Using cache
 ---> cf92d174c9d3
Step 3/4 : COPY uptimer.py app.py
 ---> a7fbb33d6b7e
Step 4/4 : CMD [ "python", "-u", "./app.py" ]
 ---> Running in 1906b4bd9fdf
Removing intermediate container 1906b4bd9fdf
 ---> c1655b996fe8
Successfully built c1655b996fe8
Successfully tagged uptimer:latest

$ docker run --rm --detach --name uptimer --publish 8080:8080 uptimer
8f88c944b8bf78974a5727070a94c76aa0b9bb2b3ecf6324b784e782614b2fbf

$ docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
8f88c944b8bf        uptimer             "python -u ./app.py"   3 seconds ago       Up 5 seconds        0.0.0.0:8080->8080/tcp   uptimer

$ docker logs uptimer
Uptimer v1.0 (loads in 10 sec.) started.

$ wget -qSO- http://localhost:8080
  HTTP/1.0 503 Service Unavailable
  Server: BaseHTTP/0.6 Python/3.8.3
  Date: Sat, 22 Aug 2020 19:52:40 GMT
  Connection: close
  Content-Type: text/html;charset=utf-8
  Content-Length: 484

$ wget -qSO- http://localhost:8080
  HTTP/1.0 200 OK
  Server: BaseHTTP/0.6 Python/3.8.3
  Date: Sat, 22 Aug 2020 19:52:45 GMT
  Content-Type: text/html
<h2>Uptimer v1.0 is running for 15.4 seconds.</h2>

$ docker rm --force uptimer
uptimer

Rov qab proxy

Yuav kom peb daim ntawv thov hloov nws tus kheej yam tsis muaj neeg pom, nws yuav tsum muaj lwm yam nyob rau pem hauv ntej uas yuav zais qhov kev hloov pauv. Qhov no yuav yog lub web server. nginx в hom rov qab proxyMuaj ib qho reverse proxy ntsia nruab nrab ntawm tus neeg siv khoom thiab daim ntawv thov. Nws tau txais cov lus thov los ntawm cov neeg siv khoom thiab xa mus rau daim ntawv thov, thiab cov lus teb ntawm daim ntawv thov raug xa rov qab mus rau cov neeg siv khoom.

Daim ntawv thov thiab tus neeg sawv cev rov qab tuaj yeem txuas hauv Docker siv Docker networkQhov no txhais tau tias lub thawv ntawv thov tsis tas yuav xa mus rau qhov chaw nres nkoj ntawm lub kaw lus tswj hwm, uas tso cai rau kev cais tawm ntau tshaj plaws ntawm daim ntawv thov los ntawm kev hem thawj sab nraud.

Yog tias tus reverse proxy yuav nyob ntawm lwm lub host, koj yuav tsum tso tseg Docker network thiab txuas daim ntawv thov rau tus reverse proxy los ntawm lub host network los ntawm kev xa mus rau qhov chaw nres nkoj. apps parameter --publish, zoo li thaum thawj zaug tso tawm thiab zoo li nrog tus neeg sawv cev rov qab.

Peb yuav khiav lub reverse proxy ntawm qhov chaw nres nkoj 80, vim qhov no yog qhov chaw uas yuav tsum mloog cov kev sib txuas sab nraud. Yog tias qhov chaw nres nkoj 80 nyob hauv koj lub test host, hloov qhov parameter. --publish 80:80 rau --publish ANY_FREE_PORT:80.

Cov txheej txheem nthuav

Luam Tawm

$ docker network create web-gateway
5dba128fb3b255b02ac012ded1906b7b4970b728fb7db3dbbeccc9a77a5dd7bd

$ docker run --detach --rm --name uptimer --network web-gateway uptimer
a1105f1b583dead9415e99864718cc807cc1db1c763870f40ea38bc026e2d67f

$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer:8080
<h2>Uptimer v1.0 is running for 11.5 seconds.</h2>

$ docker run --detach --publish 80:80 --network web-gateway --name reverse-proxy nginx:alpine
80695a822c19051260c66bf60605dcb4ea66802c754037704968bc42527bf120

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                NAMES
80695a822c19        nginx:alpine        "/docker-entrypoint.…"   27 seconds ago       Up 25 seconds       0.0.0.0:80->80/tcp   reverse-proxy
a1105f1b583d        uptimer             "python -u ./app.py"     About a minute ago   Up About a minute   8080/tcp             uptimer

$ cat << EOF > uptimer.conf
server {
    listen 80;
    location / {
        proxy_pass http://uptimer:8080;
    }
}
EOF

$ docker cp ./uptimer.conf reverse-proxy:/etc/nginx/conf.d/default.conf

$ docker exec reverse-proxy nginx -s reload
2020/06/23 20:51:03 [notice] 31#31: signal process started

$ wget -qSO- http://localhost
  HTTP/1.1 200 OK
  Server: nginx/1.19.0
  Date: Sat, 22 Aug 2020 19:56:24 GMT
  Content-Type: text/html
  Transfer-Encoding: chunked
  Connection: keep-alive
<h2>Uptimer v1.0 is running for 104.1 seconds.</h2>

Kev xa tawm tsis muaj teeb meem

Peb yuav dov tawm ib qho version tshiab ntawm lub app (nrog ob npaug ntawm kev ua haujlwm pib) thiab sim xa nws mus rau qhov tsis muaj teeb meem.

Cov txheej txheem nthuav

  • echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt' — Sau cov ntawv nyeem cia my text ua ntaub ntawv /my-file.txt sab hauv lub thawv my-container.
  • cat > /my-file.txt — Sau cov ntsiab lus ntawm cov ntaub ntawv txheem rau hauv cov ntaub ntawv /dev/stdin.

Luam Tawm

$ sed -i "s/app_version = 1/app_version = 2/" uptimer.py

$ docker build --tag uptimer .
Sending build context to Docker daemon  39.94kB
Step 1/4 : FROM python:alpine
 ---> 8ecf5a48c789
Step 2/4 : EXPOSE 8080
 ---> Using cache
 ---> cf92d174c9d3
Step 3/4 : COPY uptimer.py app.py
 ---> 3eca6a51cb2d
Step 4/4 : CMD [ "python", "-u", "./app.py" ]
 ---> Running in 8f13c6d3d9e7
Removing intermediate container 8f13c6d3d9e7
 ---> 1d56897841ec
Successfully built 1d56897841ec
Successfully tagged uptimer:latest

$ docker run --detach --rm --name uptimer_BLUE --network web-gateway uptimer
96932d4ca97a25b1b42d1b5f0ede993b43f95fac3c064262c5c527e16c119e02

$ docker logs uptimer_BLUE
Uptimer v2.0 (loads in 5 sec.) started.

$ docker run --rm --network web-gateway alpine wget -qO- http://uptimer_BLUE:8080
<h2>Uptimer v2.0 is running for 23.9 seconds.</h2>

$ sed s/uptimer/uptimer_BLUE/ uptimer.conf | docker exec --interactive reverse-proxy sh -c 'cat > /etc/nginx/conf.d/default.conf'

$ docker exec reverse-proxy cat /etc/nginx/conf.d/default.conf
server {
    listen 80;
    location / {
        proxy_pass http://uptimer_BLUE:8080;
    }
}

$ docker exec reverse-proxy nginx -s reload
2020/06/25 21:22:23 [notice] 68#68: signal process started

$ wget -qO- http://localhost
<h2>Uptimer v2.0 is running for 63.4 seconds.</h2>

$ docker rm -f uptimer
uptimer

$ wget -qO- http://localhost
<h2>Uptimer v2.0 is running for 84.8 seconds.</h2>

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                NAMES
96932d4ca97a        uptimer             "python -u ./app.py"     About a minute ago   Up About a minute   8080/tcp             uptimer_BLUE
80695a822c19        nginx:alpine        "/docker-entrypoint.…"   8 minutes ago        Up 8 minutes        0.0.0.0:80->80/tcp   reverse-proxy

Nyob rau theem no, daim duab raug tsim ncaj qha rau ntawm lub server, uas yuav tsum muaj cov lej ntawm daim ntawv thov thiab tseem tso cov haujlwm tsis tsim nyog rau ntawm lub server. Kauj ruam tom ntej yog cais cov duab tsim rau hauv lub tshuab sib cais (piv txwv li, lub kaw lus CI) thiab tom qab ntawd xa mus rau lub server.

Kev xa cov duab

Hmoov tsis zoo, kev hloov cov duab los ntawm localhost mus rau localhost tsis muaj txiaj ntsig, yog li ntu no tsuas yog tuaj yeem tshawb nrhiav nrog ob lub hosts khiav Docker. Yam tsawg kawg nkaus, nws zoo li qhov no:

$ ssh production-server docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

$ docker image save uptimer | ssh production-server 'docker image load'
Loaded image: uptimer:latest

$ ssh production-server docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
uptimer             latest              1d56897841ec        5 minutes ago       78.9MB

pab neeg docker save Txuag cov ntaub ntawv duab rau hauv .tar archive, txhais tau tias nws loj dua li 1.5 npaug ntawm nws yuav yog tias compressed. Yog li cia peb compress nws kom txuag lub sijhawm thiab bandwidth:

$ docker image save uptimer | gzip | ssh production-server 'zcat | docker image load'
Loaded image: uptimer:latest

Koj tuaj yeem saib xyuas cov txheej txheem rub tawm (txawm hais tias koj yuav xav tau cov cuab yeej siv thib peb rau qhov no):

$ docker image save uptimer | gzip | pv | ssh production-server 'zcat | docker image load'
25,7MiB 0:01:01 [ 425KiB/s] [                   <=>    ]
Loaded image: uptimer:latest

Lub Tswv Yim: Yog tias koj xav tau ntau yam kev teeb tsa los txuas rau lub server ntawm SSH, tej zaum koj yuav tsis siv cov ntaub ntawv ~/.ssh/config.

Hloov daim duab ntawm docker image save/load — Qhov no yog txoj kev yooj yim tshaj plaws, tab sis tsis yog tib txoj kev xwb. Muaj lwm txoj hauv kev:

  1. Lub Thawv Sau Npe (tus qauv kev lag luam).
  2. Txuas rau lub docker daemon server los ntawm lwm tus tswv tsev:
    1. Ib puag ncig hloov pauv DOCKER_HOST.
    2. Cov lus txib parameter -H los yog --host ntsuas docker-compose.
    3. docker context

Txoj kev thib ob (nrog peb txoj kev xaiv rau nws txoj kev siv) tau piav qhia zoo hauv tsab xov xwm Yuav ua li cas rau deploy rau ntawm Docker hosts chaw taws teeb nrog docker-compose.

deploy.sh

Tam sim no cia peb muab txhua yam uas peb tau ua tes ua ke rau hauv ib tsab ntawv xwb. Peb mam li pib nrog lub luag haujlwm theem siab tshaj plaws, thiab tom qab ntawd saib lwm yam uas siv hauv nws.

Cov txheej txheem nthuav

  • ${parameter?err_msg} — ib qho ntawm cov khawv koob bash (aka kev hloov pauv parameter). Yog tias parameter tsis tau teev tseg, tso zis err_msg thiab tawm nrog code 1.
  • docker --log-driver journald Los ntawm lub neej ntawd, Docker tus tsav tsheb sau ntawv yog cov ntaub ntawv ntawv tsis muaj kev tig. Nrog txoj hauv kev no, cov cav sau sai sai ua rau lub disk puv, yog li rau cov chaw tsim khoom, koj yuav tsum hloov tus tsav tsheb mus rau qhov ntse dua.

Tsab ntawv xa tawm

deploy() {
    local usage_msg="Usage: ${FUNCNAME[0]} image_name"
    local image_name=${1?$usage_msg}

    ensure-reverse-proxy || return 2
    if get-active-slot $image_name
    then
        local OLD=${image_name}_BLUE
        local new_slot=GREEN
    else
        local OLD=${image_name}_GREEN
        local new_slot=BLUE
    fi
    local NEW=${image_name}_${new_slot}
    echo "Deploying '$NEW' in place of '$OLD'..."
    docker run 
        --detach 
        --restart always 
        --log-driver journald 
        --name $NEW 
        --network web-gateway 
        $image_name || return 3
    echo "Container started. Checking health..."
    for i in {1..20}
    do
        sleep 1
        if get-service-status $image_name $new_slot
        then
            echo "New '$NEW' service seems OK. Switching heads..."
            sleep 2  # Ensure service is ready
            set-active-slot $image_name $new_slot || return 4
            echo "'$NEW' service is live!"
            sleep 2  # Ensure all requests were processed
            echo "Killing '$OLD'..."
            docker rm -f $OLD
            docker image prune -f
            echo "Deployment successful!"
            return 0
        fi
        echo "New '$NEW' service is not ready yet. Waiting ($i)..."
    done
    echo "New '$NEW' service did not raise, killing it. Failed to deploy T_T"
    docker rm -f $NEW
    return 5
}

Cov haujlwm siv:

  • ensure-reverse-proxy — Xyuas kom tseeb tias tus reverse proxy ua haujlwm (muaj txiaj ntsig rau thawj zaug xa tawm)
  • get-active-slot service_name — Txheeb xyuas seb qhov twg tam sim no ua haujlwm rau ib qho kev pabcuam (BLUE los yog GREEN)
  • get-service-status service_name deployment_slot — Txheeb xyuas seb qhov kev pabcuam puas npaj txhij los ua cov lus thov tuaj
  • set-active-slot service_name deployment_slot — Hloov cov nginx configuration hauv lub thawv reverse proxy

Hauv kev txiav txim:

ensure-reverse-proxy() {
    is-container-up reverse-proxy && return 0
    echo "Deploying reverse-proxy..."
    docker network create web-gateway
    docker run 
        --detach 
        --restart always 
        --log-driver journald 
        --name reverse-proxy 
        --network web-gateway 
        --publish 80:80 
        nginx:alpine || return 1
    docker exec --interactive reverse-proxy sh -c "> /etc/nginx/conf.d/default.conf"
    docker exec reverse-proxy nginx -s reload
}

is-container-up() {
    local container=${1?"Usage: ${FUNCNAME[0]} container_name"}

    [ -n "$(docker ps -f name=${container} -q)" ]
    return $?
}

get-active-slot() {
    local service=${1?"Usage: ${FUNCNAME[0]} service_name"}

    if is-container-up ${service}_BLUE && is-container-up ${service}_GREEN; then
        echo "Collision detected! Stopping ${service}_GREEN..."
        docker rm -f ${service}_GREEN
        return 0  # BLUE
    fi
    if is-container-up ${service}_BLUE && ! is-container-up ${service}_GREEN; then
        return 0  # BLUE
    fi
    if ! is-container-up ${service}_BLUE; then
        return 1  # GREEN
    fi
}

get-service-status() {
    local usage_msg="Usage: ${FUNCNAME[0]} service_name deployment_slot"
    local service=${1?usage_msg}
    local slot=${2?$usage_msg}

    case $service in
        # Add specific healthcheck paths for your services here
        *) local health_check_port_path=":8080/" ;;
    esac
    local health_check_address="http://${service}_${slot}${health_check_port_path}"
    echo "Requesting '$health_check_address' within the 'web-gateway' docker network:"
    docker run --rm --network web-gateway alpine 
        wget --timeout=1 --quiet --server-response $health_check_address
    return $?
}

set-active-slot() {
    local usage_msg="Usage: ${FUNCNAME[0]} service_name deployment_slot"
    local service=${1?$usage_msg}
    local slot=${2?$usage_msg}
    [ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1

    get-nginx-config $service $slot | docker exec --interactive reverse-proxy sh -c "cat > /etc/nginx/conf.d/$service.conf"
    docker exec reverse-proxy nginx -t || return 2
    docker exec reverse-proxy nginx -s reload
}

muaj nuj nqi get-active-slot xav tau kev piav qhia me ntsis:

Vim li cas nws thiaj rov qab los ua tus lej es tsis txhob luam tawm ib txoj hlua?

Peb tseem xyuas qhov tshwm sim ntawm kev ua haujlwm hauv kev hu xov tooj, thiab kev kuaj xyuas cov lej tawm nrog bash yooj yim dua li kev kuaj xyuas cov hlua. Ntxiv mus, kev tau txais cov hlua los ntawm nws yooj yim heev:
get-active-slot service && echo BLUE || echo GREEN.

Puas muaj peb yam mob txaus los cais txhua lub xeev?

Blue-Green Deployment ntawm cov nyiaj ua haujlwm yam tsawg kawg nkaus

Txawm tias ob tug los yeej txaus lawm, qhov kawg yog nyob ntawm no kom tiav xwb, yog li ntawd tsis txhob sau ntawv else.

Tsuas muaj ib qho function uas tseem tsis tau txhais yog qhov uas rov qab nginx configs: get-nginx-config service_name deployment_slotZoo li kev kuaj mob, koj tuaj yeem teeb tsa txhua yam kev teeb tsa rau txhua qhov kev pabcuam ntawm no. Tsuas yog qhov nthuav yog cat <<- EOF, uas tshem tawm tag nrho cov tabs thaum pib. Txawm li cas los xij, tus nqi ntawm kev tsim qauv zoo yog sib xyaw tabs thiab qhov chaw, uas suav tias yog daim ntawv phem heev hnub no. Tab sis bash yuam cov tabs, thiab kev tsim qauv kom zoo kuj yuav zoo hauv nginx config. Hauv ntej, kev sib xyaw tabs thiab qhov chaw zoo li qhov zoo tshaj plaws ntawm ib pawg phem. Txawm li cas los xij, koj yuav tsis pom qhov no hauv snippet hauv qab no, txij li Habr "ua nws zoo" los ntawm kev hloov tag nrho cov tabs rau plaub qhov chaw thiab tsis lees paub EOF. Thiab ntawm no nws pom tseeb.

Yog li ntawd kuv thiaj tsis tas yuav sawv ob zaug, kuv mam li qhia koj tam sim ntawd txog cat << 'EOF', uas yuav ntsib ntxiv mus. Yog tias peb sau yooj yim cat << EOF, ces sab hauv heredoc, string interpolation yog ua (cov hloov pauv tau nthuav dav ($foo), kev hu xov tooj txib ($(bar)) thiab lwm yam), thiab yog tias koj muab lub cim kawg ntawm daim ntawv tso rau hauv cov lus cim ib leeg, ces kev sib txuas lus raug kaw thiab lub cim $ Nws tso zis raws li nws yog. Qhov no yog qhov koj xav tau los ntxig ib tsab ntawv rau hauv lwm tsab ntawv.

get-nginx-config() {
    local usage_msg="Usage: ${FUNCNAME[0]} service_name deployment_slot"
    local service=${1?$usage_msg}
    local slot=${2?$usage_msg}
    [ "$slot" == BLUE ] || [ "$slot" == GREEN ] || return 1

    local container_name=${service}_${slot}
    case $service in
        # Add specific nginx configs for your services here
        *) nginx-config-simple-service $container_name:8080 ;;
    esac
}

nginx-config-simple-service() {
    local usage_msg="Usage: ${FUNCNAME[0]} proxy_pass"
    local proxy_pass=${1?$usage_msg}

cat << EOF
server {
    listen 80;
    location / {
        proxy_pass http://$proxy_pass;
    }
}
EOF
}

Nov yog tsab ntawv tag nrho. Thiab ntawm no nws yog keeb kwm nrog tsab ntawv no rau rub tawm ntawm wget lossis curl.

Ua cov ntawv sau parameterized ntawm lub server nyob deb

Nws yog lub sijhawm los khob rau ntawm lub server uas koj xav tau. Lub sijhawm no localhost yuav ua tau zoo xwb:

$ ssh-copy-id localhost
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
himura@localhost's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'localhost'"
and check to make sure that only the key(s) you wanted were added.

Peb tau sau ib tsab ntawv xa tawm uas thawb ib daim duab uas tau tsim ua ntej mus rau lub server thiab hloov pauv lub thawv kev pabcuam, tab sis peb yuav ua li cas rau ntawm lub tshuab nyob deb? Tsab ntawv muaj cov lus sib cav vim nws yog thoob ntiaj teb thiab tuaj yeem xa ntau yam kev pabcuam rau ib qho reverse proxy (NGINX configurations tuaj yeem siv los qhia qhov URL kev pabcuam twg yuav raug siv). Tsab ntawv tsis tuaj yeem khaws cia rau ntawm lub server, vim qhov no yuav tiv thaiv peb los ntawm kev hloov kho nws (rau kev kho kab laum thiab ntxiv cov kev pabcuam tshiab), thiab, txawm li cas los xij, lub xeev = phem.

Kev daws teeb meem 1: Khaws cov ntawv sau rau ntawm lub server, tab sis theej nws txhua zaus scp. Ces txuas ntawm ssh thiab ua tiav cov ntawv sau nrog cov lus sib cav uas xav tau.

Txais:

  • Ob qho kev ua es tsis yog ib qho
  • Qhov chaw uas koj theej mus rau tej zaum yuav tsis muaj, lossis koj yuav tsis muaj cai nkag mus rau nws, lossis tsab ntawv yuav khiav thaum lub sijhawm hloov chaw.
  • Nws yog ib qho tsim nyog los ntxuav tom qab koj tus kheej (rho tawm tsab ntawv sau).
  • Peb qhov kev ua twb muaj lawm.

Kev daws 2:

  • Daim ntawv sau yuav tsum tsuas muaj cov lus txhais txog kev ua haujlwm xwb thiab tsis khiav dab tsi li.
  • Nrog kev pab los ntawm sed ntxiv ib qho kev hu ua haujlwm rau qhov kawg
  • Xa tag nrho cov no ncaj qha mus rau shh ntawm cov yeeb nkab (|)

Tshaj:

  • Tsis muaj lub xeev tiag tiag
  • Tsis muaj cov qauv boilerplate
  • Xav txias

Cia peb ua nws yam tsis muaj Ansible. Yog lawm, nws tau raug xam tawm tag nrho. Yog lawm, lub tsheb kauj vab. Saib seb nws yooj yim npaum li cas, zoo nkauj, thiab minimalist:

$ cat << 'EOF' > deploy.sh
#!/bin/bash

usage_msg="Usage: $0 ssh_address local_image_tag"
ssh_address=${1?$usage_msg}
image_name=${2?$usage_msg}

echo "Connecting to '$ssh_address' via ssh to seamlessly deploy '$image_name'..."
( sed "$a deploy $image_name" | ssh -T $ssh_address ) << 'END_OF_SCRIPT'
deploy() {
    echo "Yay! The '${FUNCNAME[0]}' function is executing on '$(hostname)' with argument '$1'"
}
END_OF_SCRIPT
EOF

$ chmod +x deploy.sh

$ ./deploy.sh localhost magic-porridge-pot
Connecting to localhost...
Yay! The 'deploy' function is executing on 'hut' with argument 'magic-porridge-pot'

Txawm li cas los xij, peb tsis tuaj yeem paub tseeb tias tus tswv tsev nyob deb muaj bash txaus, yog li peb yuav ntxiv ib qho kev kuaj xyuas me me thaum pib (qhov no yog hloov chaw lub foob pob tawg):

if [ "$SHELL" != "/bin/bash" ]
then
    echo "The '$SHELL' shell is not supported by 'deploy.sh'. Set a '/bin/bash' shell for '$USER@$HOSTNAME'."
    exit 1
fi

Thiab tam sim no nws yog txhua yam rau qhov tseeb:

$ docker exec reverse-proxy rm /etc/nginx/conf.d/default.conf

$ wget -qO deploy.sh https://git.io/JUURc

$ chmod +x deploy.sh

$ ./deploy.sh localhost uptimer
Sending gzipped image 'uptimer' to 'localhost' via ssh...
Loaded image: uptimer:latest
Connecting to 'localhost' via ssh to seamlessly deploy 'uptimer'...
Deploying 'uptimer_GREEN' in place of 'uptimer_BLUE'...
06f5bc70e9c4f930e7b1f826ae2ca2f536023cc01e82c2b97b2c84d68048b18a
Container started. Checking health...
Requesting 'http://uptimer_GREEN:8080/' within the 'web-gateway' docker network:
  HTTP/1.0 503 Service Unavailable
wget: server returned error: HTTP/1.0 503 Service Unavailable
New 'uptimer_GREEN' service is not ready yet. Waiting (1)...
Requesting 'http://uptimer_GREEN:8080/' within the 'web-gateway' docker network:
  HTTP/1.0 503 Service Unavailable
wget: server returned error: HTTP/1.0 503 Service Unavailable
New 'uptimer_GREEN' service is not ready yet. Waiting (2)...
Requesting 'http://uptimer_GREEN:8080/' within the 'web-gateway' docker network:
  HTTP/1.0 200 OK
  Server: BaseHTTP/0.6 Python/3.8.3
  Date: Sat, 22 Aug 2020 20:15:50 GMT
  Content-Type: text/html

New 'uptimer_GREEN' service seems OK. Switching heads...
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
2020/08/22 20:15:54 [notice] 97#97: signal process started
The 'uptimer_GREEN' service is live!
Killing 'uptimer_BLUE'...
uptimer_BLUE
Total reclaimed space: 0B
Deployment successful!

Tam sim no koj tuaj yeem qhib nws http://localhost/ hauv browser, khiav qhov kev xa tawm dua thiab xyuas kom meej tias nws khiav tsis muaj teeb meem los ntawm kev ua kom nplooj ntawv tshiab raws li CD thaum lub sijhawm xa tawm.

Tsis txhob hnov ​​qab ntxuav tom qab ua haujlwm :3

$ docker rm -f uptimer_GREEN reverse-proxy 
uptimer_GREEN
reverse-proxy

$ docker network rm web-gateway 
web-gateway

$ cd ..

$ rm -r blue-green-deployment

Tau qhov twg los: www.hab.com