āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ āĻŽāĻœā§āĻ°āĻŋāĻ¤ā§‡ āĻ¨ā§€āĻ˛-āĻ¸āĻŦā§āĻœ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻž

āĻāĻ‡ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§‡ āĻ†āĻŽāĻ°āĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŋ āĻ¸āĻœā§‹āĻ°ā§‡ āĻ†āĻ˜āĻžāĻ¤, SSH, āĻĄāĻ•āĻļā§āĻ°āĻŽāĻŋāĻ• и nginx āĻ†āĻŽāĻ°āĻž āĻ“āĻ¯āĻŧā§‡āĻŦ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻ°āĻžāĻŽāĻšā§€āĻ¨ āĻŦāĻŋāĻ¨ā§āĻ¯āĻžāĻ¸ āĻ¸āĻ‚āĻ—āĻ āĻŋāĻ¤ āĻ•āĻ°āĻŦāĨ¤ āĻ¨ā§€āĻ˛-āĻ¸āĻŦā§āĻœ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻž āĻāĻ•āĻŸāĻŋ āĻ•ā§ŒāĻļāĻ˛ āĻ¯āĻž āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ…āĻŦāĻŋāĻ˛āĻŽā§āĻŦā§‡ āĻāĻ•āĻŸāĻŋ āĻ†āĻŦā§‡āĻĻāĻ¨ āĻĒā§āĻ°āĻ¤ā§āĻ¯āĻžāĻ–ā§āĻ¯āĻžāĻ¨ āĻ¨āĻž āĻ•āĻ°ā§‡āĻ‡ āĻ†āĻĒāĻĄā§‡āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĻā§‡āĻ¯āĻŧā§ˇ āĻāĻŸāĻŋ āĻļā§‚āĻ¨ā§āĻ¯ āĻĄāĻžāĻ‰āĻ¨āĻŸāĻžāĻ‡āĻŽ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻžāĻ° āĻ•ā§ŒāĻļāĻ˛āĻ—ā§āĻ˛āĻŋāĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻāĻ•āĻŸāĻŋ āĻāĻŦāĻ‚ āĻāĻ•āĻŸāĻŋ āĻĻā§ƒāĻˇā§āĻŸāĻžāĻ¨ā§āĻ¤ āĻ¸āĻš āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻ—ā§āĻ˛āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻ¸āĻŦāĻšā§‡āĻ¯āĻŧā§‡ āĻ‰āĻĒāĻ¯ā§āĻ•ā§āĻ¤, āĻ¤āĻŦā§‡ āĻ•āĻžāĻ›āĻžāĻ•āĻžāĻ›āĻŋ āĻāĻ•āĻŸāĻŋ āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄ, āĻ°ā§‡āĻĄāĻŋ-āĻŸā§-āĻ°āĻžāĻ¨ āĻ‡āĻ¨āĻ¸ā§āĻŸā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻžāĻ° āĻ•ā§āĻˇāĻŽāĻ¤āĻžāĨ¤

āĻ§āĻ°āĻž āĻ¯āĻžāĻ• āĻ†āĻĒāĻ¨āĻžāĻ° āĻāĻ•āĻŸāĻŋ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡ āĻ¯āĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ…āĻ¨ā§‡āĻ• āĻ•ā§āĻ˛āĻžāĻ¯āĻŧā§‡āĻ¨ā§āĻŸ āĻ¸āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻ­āĻžāĻŦā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻ›ā§‡ āĻāĻŦāĻ‚ āĻ•āĻ¯āĻŧā§‡āĻ• āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻļā§āĻ¯āĻŧā§‡ āĻĨāĻžāĻ•āĻžāĻ° āĻ•ā§‹āĻ¨ āĻ‰āĻĒāĻžāĻ¯āĻŧ āĻ¨ā§‡āĻ‡āĨ¤ āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ¸āĻ¤ā§āĻ¯āĻŋāĻ‡ āĻāĻ•āĻŸāĻŋ āĻ˛āĻžāĻ‡āĻŦā§āĻ°ā§‡āĻ°āĻŋ āĻ†āĻĒāĻĄā§‡āĻŸ, āĻāĻ•āĻŸāĻŋ āĻŦāĻžāĻ— āĻĢāĻŋāĻ•ā§āĻ¸, āĻŦāĻž āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻĻā§āĻ°ā§āĻĻāĻžāĻ¨ā§āĻ¤ āĻŦā§ˆāĻļāĻŋāĻˇā§āĻŸā§āĻ¯ āĻ°ā§‹āĻ˛ āĻ†āĻ‰āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻŦāĻžāĻ­āĻžāĻŦāĻŋāĻ• āĻĒāĻ°āĻŋāĻ¸ā§āĻĨāĻŋāĻ¤āĻŋāĻ¤ā§‡, āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋ āĻŦāĻ¨ā§āĻ§ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡, āĻāĻŸāĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻāĻŸāĻŋ āĻ†āĻŦāĻžāĻ° āĻļā§āĻ°ā§ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻĄāĻ•āĻžāĻ°ā§‡āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻĒā§āĻ°āĻĨāĻŽā§‡ āĻāĻŸāĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻāĻŸāĻŋ āĻĒā§āĻ¨āĻ°āĻžāĻ¯āĻŧ āĻšāĻžāĻ˛ā§ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻ¤āĻŦā§‡ āĻāĻ–āĻ¨āĻ“ āĻāĻ•āĻŸāĻŋ āĻ¸āĻŽāĻ¯āĻŧ āĻĨāĻžāĻ•āĻŦā§‡ āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ—ā§āĻ˛āĻŋ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻ¨āĻž, āĻ•āĻžāĻ°āĻŖ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖāĻ¤ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋ āĻĒā§āĻ°āĻžāĻĨāĻŽāĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻ˛ā§‹āĻĄ āĻšāĻ¤ā§‡ āĻ•āĻŋāĻ›ā§āĻŸāĻž āĻ¸āĻŽāĻ¯āĻŧ āĻ¨ā§‡āĻ¯āĻŧāĨ¤ āĻāĻŸāĻž āĻļā§āĻ°ā§ āĻšāĻ˛ā§‡ āĻ•āĻŋ āĻšāĻŦā§‡, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻ…āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻšāĻ¤ā§‡ āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻšā§āĻ›ā§‡? āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž, āĻ†āĻ¸ā§āĻ¨ āĻāĻŸāĻŋāĻ•ā§‡ āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ āĻ‰āĻĒāĻžāĻ¯āĻŧā§‡ āĻāĻŦāĻ‚ āĻ¯āĻ¤āĻŸāĻž āĻ¸āĻŽā§āĻ­āĻŦ āĻŽāĻžāĻ°ā§āĻœāĻŋāĻ¤āĻ­āĻžāĻŦā§‡ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻ•āĻ°āĻŋāĨ¤

āĻ…āĻ¸ā§āĻŦā§€āĻ•ā§ƒāĻ¤āĻŋ: āĻŦā§‡āĻļāĻŋāĻ°āĻ­āĻžāĻ— āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ āĻāĻ•āĻŸāĻŋ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻžāĻŽā§‚āĻ˛āĻ• āĻŦāĻŋāĻ¨ā§āĻ¯āĻžāĻ¸ā§‡ āĻ‰āĻĒāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡ - āĻāĻ•āĻŸāĻŋ āĻ•āĻ¨āĻ¸ā§‹āĻ˛ āĻ¸ā§‡āĻļāĻ¨ā§‡āĻ° āĻ°ā§‡āĻ•āĻ°ā§āĻĄāĻŋāĻ‚āĻ¯āĻŧā§‡āĻ° āĻ†āĻ•āĻžāĻ°ā§‡āĨ¤ āĻ†āĻļāĻž āĻ•āĻ°āĻŋ āĻāĻŸāĻŋ āĻŦā§‹āĻāĻž āĻ–ā§āĻŦ āĻ•āĻ āĻŋāĻ¨ āĻšāĻŦā§‡ āĻ¨āĻž āĻāĻŦāĻ‚ āĻ•ā§‹āĻĄāĻŸāĻŋ āĻ¯āĻĨā§‡āĻˇā§āĻŸ āĻ¨āĻĨāĻŋāĻ­ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻŦā§‡āĨ¤ āĻŦāĻžāĻ¯āĻŧā§āĻŽāĻŖā§āĻĄāĻ˛ā§‡āĻ° āĻœāĻ¨ā§āĻ¯, āĻ•āĻ˛ā§āĻĒāĻ¨āĻž āĻ•āĻ°ā§āĻ¨ āĻ¯ā§‡ āĻāĻ—ā§āĻ˛āĻŋ āĻ•ā§‡āĻŦāĻ˛ āĻ•ā§‹āĻĄ āĻ¸ā§āĻ¨āĻŋāĻĒā§‡āĻŸ āĻ¨āĻ¯āĻŧ, āĻāĻ•āĻŸāĻŋ "āĻ˛ā§‹āĻšāĻž" āĻŸā§‡āĻ˛āĻŋāĻŸāĻžāĻ‡āĻĒ āĻĨā§‡āĻ•ā§‡ āĻ•āĻžāĻ—āĻœāĨ¤

āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ āĻŽāĻœā§āĻ°āĻŋāĻ¤ā§‡ āĻ¨ā§€āĻ˛-āĻ¸āĻŦā§āĻœ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻž

āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ•ā§‹āĻĄ āĻĒāĻĄāĻŧā§‡ Google-āĻāĻ° āĻ•āĻžāĻ›ā§‡ āĻ•āĻ āĻŋāĻ¨ āĻāĻŽāĻ¨ āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ āĻ•ā§ŒāĻļāĻ˛ āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŦāĻŋāĻ­āĻžāĻ—ā§‡āĻ° āĻļā§āĻ°ā§āĻ¤ā§‡ āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ āĻ…āĻ¨ā§āĻ¯ āĻ•āĻŋāĻ›ā§ āĻ…āĻ¸ā§āĻĒāĻˇā§āĻŸ āĻšāĻ˛ā§‡, āĻāĻŸāĻŋ āĻ—ā§āĻ—āĻ˛ āĻ•āĻ°ā§āĻ¨ āĻāĻŦāĻ‚ āĻāĻŸāĻŋ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻž āĻ•āĻ°ā§‡ āĻĻā§‡āĻ–ā§āĻ¨. āĻŦā§āĻ¯āĻžāĻ–ā§āĻ¯āĻž (āĻ¸ā§ŒāĻ­āĻžāĻ—ā§āĻ¯āĻŦāĻļāĻ¤, āĻŸā§‡āĻ˛āĻŋāĻ—ā§āĻ°āĻžāĻŽ āĻ†āĻ¨āĻŦā§āĻ˛āĻ• āĻ•āĻ°āĻžāĻ° āĻ•āĻžāĻ°āĻŖā§‡ āĻāĻŸāĻŋ āĻ†āĻŦāĻžāĻ° āĻ•āĻžāĻœ āĻ•āĻ°ā§‡)āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻ•āĻŋāĻ›ā§ Google āĻ•āĻ°āĻ¤ā§‡ āĻ¨āĻž āĻĒāĻžāĻ°ā§‡āĻ¨, āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯ā§‡ āĻœāĻŋāĻœā§āĻžāĻžāĻ¸āĻž āĻ•āĻ°ā§āĻ¨. āĻ†āĻŽāĻŋ āĻ¸āĻ‚āĻļā§āĻ˛āĻŋāĻˇā§āĻŸ āĻŦāĻŋāĻ­āĻžāĻ—ā§‡ "āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ āĻ•ā§ŒāĻļāĻ˛" āĻ¯ā§‹āĻ— āĻ•āĻ°āĻ¤ā§‡ āĻĒā§‡āĻ°ā§‡ āĻ–ā§āĻļāĻŋ āĻšāĻŦāĨ¤

āĻļā§āĻ°ā§ āĻ•āĻ°āĻž āĻ¯āĻžāĻ•āĨ¤

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

āĻ¸ā§‡āĻŦāĻž

āĻ†āĻ¸ā§āĻ¨ āĻāĻ•āĻŸāĻŋ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻžāĻŽā§‚āĻ˛āĻ• āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻĒāĻžāĻ¤ā§āĻ°ā§‡ āĻ°āĻžāĻ–āĻŋāĨ¤

āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ āĻ•ā§ŒāĻļāĻ˛

  • cat << EOF > file-name (āĻāĻ–āĻžāĻ¨ā§‡ āĻĄāĻ•ā§āĻŽā§‡āĻ¨ā§āĻŸ + I/O āĻĒā§āĻ¨āĻ°ā§āĻ¨āĻŋāĻ°ā§āĻĻā§‡āĻļ) āĻšāĻ˛ āĻāĻ•āĻŸāĻŋ āĻ•āĻŽāĻžāĻ¨ā§āĻĄ āĻ¸āĻš āĻāĻ•āĻŸāĻŋ āĻŽāĻžāĻ˛ā§āĻŸāĻŋ-āĻ˛āĻžāĻ‡āĻ¨ āĻĢāĻžāĻ‡āĻ˛ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻžāĻ° āĻāĻ•āĻŸāĻŋ āĻ‰āĻĒāĻžāĻ¯āĻŧāĨ¤ āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻŦāĻžāĻļ āĻĨā§‡āĻ•ā§‡ āĻĒāĻĄāĻŧāĻž /dev/stdin āĻāĻ‡ āĻ˛āĻžāĻ‡āĻ¨ā§‡āĻ° āĻĒāĻ°ā§‡ āĻāĻŦāĻ‚ āĻ˛āĻžāĻ‡āĻ¨ā§‡āĻ° āĻ†āĻ—ā§‡ EOF āĻŽāĻ§ā§āĻ¯ā§‡ āĻ°ā§‡āĻ•āĻ°ā§āĻĄ āĻ•āĻ°āĻž āĻšāĻŦā§‡ file-name.
  • wget -qO- URL (āĻŦā§āĻ¯āĻžāĻ–ā§āĻ¯āĻž) — HTTP āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻĒā§āĻ°āĻžāĻĒā§āĻ¤ āĻāĻ•āĻŸāĻŋ āĻ¨āĻĨāĻŋ āĻ†āĻ‰āĻŸāĻĒā§āĻŸ āĻ•āĻ°ā§‡ /dev/stdout (āĻ…ā§āĻ¯āĻžāĻ¨āĻžāĻ˛āĻ— curl URL).

āĻĒā§āĻ°āĻŋāĻ¨ā§āĻŸāĻ†āĻ‰āĻŸ

āĻĒāĻžāĻ‡āĻĨāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻšāĻžāĻ‡āĻ˛āĻžāĻ‡āĻŸāĻŋāĻ‚ āĻ¸āĻ•ā§āĻˇāĻŽ āĻ•āĻ°āĻ¤ā§‡ āĻ†āĻŽāĻŋ āĻŦāĻŋāĻļā§‡āĻˇāĻ­āĻžāĻŦā§‡ āĻ¸ā§āĻ¨āĻŋāĻĒā§‡āĻŸāĻŸāĻŋ āĻ­ā§‡āĻ™ā§‡ āĻĻāĻŋāĻ‡āĨ¤ āĻļā§‡āĻˇā§‡ āĻāĻ‡ āĻŽāĻ¤ āĻ†āĻ°ā§‡āĻ•āĻŸāĻŋ āĻŸā§āĻ•āĻ°āĻž āĻšāĻŦā§‡. āĻŦāĻŋāĻŦā§‡āĻšāĻ¨āĻž āĻ•āĻ°ā§āĻ¨ āĻ¯ā§‡ āĻāĻ‡ āĻœāĻžāĻ¯āĻŧāĻ—āĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ•āĻžāĻ—āĻœāĻŸāĻŋ āĻšāĻžāĻ‡āĻ˛āĻžāĻ‡āĻŸāĻŋāĻ‚ āĻŦāĻŋāĻ­āĻžāĻ—ā§‡ āĻĒāĻžāĻ āĻžāĻ¨ā§‹āĻ° āĻœāĻ¨ā§āĻ¯ āĻ•āĻžāĻŸāĻž āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛ (āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ•ā§‹āĻĄāĻŸāĻŋ āĻšāĻžāĻ‡āĻ˛āĻžāĻ‡āĻŸāĻžāĻ° āĻĻāĻŋāĻ¯āĻŧā§‡ āĻšāĻžāĻ¤ā§‡ āĻ°āĻ™ā§‡āĻ° āĻ›āĻŋāĻ˛), āĻāĻŦāĻ‚ āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻāĻ‡ āĻŸā§āĻ•āĻ°ā§‹āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ†āĻŦāĻžāĻ° āĻ†āĻ āĻžāĻ˛ā§‹ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛āĨ¤

$ 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

āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋ āĻ…āĻ˛āĻ•ā§āĻˇāĻŋāĻ¤ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻ¸āĻ•ā§āĻˇāĻŽ āĻšāĻ“āĻ¯āĻŧāĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻāĻŸāĻŋāĻ° āĻ¸āĻžāĻŽāĻ¨ā§‡ āĻ…āĻ¨ā§āĻ¯ āĻ•ā§‹āĻ¨āĻ“ āĻ¸āĻ¤ā§āĻ¤āĻž āĻĨāĻžāĻ•āĻž āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻ¯āĻž āĻāĻŸāĻŋāĻ° āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻ•ā§‡ āĻ†āĻĄāĻŧāĻžāĻ˛ āĻ•āĻ°āĻŦā§‡āĨ¤ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ° āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ nginx в āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻŽā§‹āĻĄ. āĻ•ā§āĻ˛āĻžāĻ¯āĻŧā§‡āĻ¨ā§āĻŸ āĻāĻŦāĻ‚ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻˇā§āĻ āĻŋāĻ¤ āĻšāĻ¯āĻŧāĨ¤ āĻāĻŸāĻŋ āĻ•ā§āĻ˛āĻžāĻ¯āĻŧā§‡āĻ¨ā§āĻŸāĻĻā§‡āĻ° āĻ•āĻžāĻ› āĻĨā§‡āĻ•ā§‡ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻ—ā§āĻ°āĻšāĻŖ āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻ¤āĻžāĻĻā§‡āĻ° āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡ āĻĢāĻ°ā§‹āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻ•ā§āĻ˛āĻžāĻ¯āĻŧā§‡āĻ¨ā§āĻŸāĻĻā§‡āĻ° āĻ•āĻžāĻ›ā§‡ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡āĻ° āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻĢāĻ°ā§‹āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ•āĻ°ā§‡āĨ¤

āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻāĻŦāĻ‚ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻĄāĻ•āĻžāĻ° āĻ­āĻŋāĻ¤āĻ°ā§‡ āĻ˛āĻŋāĻ™ā§āĻ• āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ āĻĄāĻ•āĻžāĻ° āĻ¨ā§‡āĻŸāĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ•. āĻ¸ā§āĻ¤āĻ°āĻžāĻ‚, āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ¸āĻš āĻ§āĻžāĻ°āĻ•āĻŸāĻŋāĻ•ā§‡ āĻšā§‹āĻ¸ā§āĻŸ āĻ¸āĻŋāĻ¸ā§āĻŸā§‡āĻŽā§‡ āĻāĻ•āĻŸāĻŋ āĻĒā§‹āĻ°ā§āĻŸ āĻĢāĻ°ā§‹āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ•āĻ°āĻžāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻ¨ā§‡āĻ‡; āĻāĻŸāĻŋ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ•ā§‡ āĻŦāĻžāĻšā§āĻ¯āĻŋāĻ• āĻšā§āĻŽāĻ•āĻŋ āĻĨā§‡āĻ•ā§‡ āĻ¸āĻ°ā§āĻŦāĻžāĻ§āĻŋāĻ• āĻŦāĻŋāĻšā§āĻ›āĻŋāĻ¨ā§āĻ¨ āĻ•āĻ°āĻžāĻ° āĻ…āĻ¨ā§āĻŽāĻ¤āĻŋ āĻĻā§‡āĻ¯āĻŧāĨ¤

āĻ¯āĻĻāĻŋ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ…āĻ¨ā§āĻ¯ āĻšā§‹āĻ¸ā§āĻŸā§‡ āĻĨāĻžāĻ•ā§‡, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻĄāĻ•āĻžāĻ° āĻ¨ā§‡āĻŸāĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ• āĻĒāĻ°āĻŋāĻ¤ā§āĻ¯āĻžāĻ— āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻšā§‹āĻ¸ā§āĻŸ āĻ¨ā§‡āĻŸāĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ•ā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ°āĻŋāĻ­āĻžāĻ°ā§āĻ¸ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ•ā§‡ āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡, āĻĒā§‹āĻ°ā§āĻŸ āĻĢāĻ°āĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻ•āĻ°ā§‡ āĻ…ā§āĻ¯āĻžāĻĒāĻ¸ āĻĒā§āĻ¯āĻžāĻ°āĻžāĻŽāĻŋāĻŸāĻžāĻ° --publish, āĻĒā§āĻ°āĻĨāĻŽ āĻļā§āĻ°ā§āĻ¤ā§‡ āĻāĻŦāĻ‚ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋāĻ° āĻŽāĻ¤ā§‹āĨ¤

āĻ†āĻŽāĻ°āĻž āĻĒā§‹āĻ°ā§āĻŸ 80-āĻ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻšāĻžāĻ˛āĻžāĻŦ, āĻ•āĻžāĻ°āĻŖ āĻāĻŸāĻŋ āĻ āĻŋāĻ• āĻ¸ā§‡āĻ‡ āĻ¸āĻ¤ā§āĻ¤āĻž āĻ¯āĻž āĻŦāĻžāĻšā§āĻ¯āĻŋāĻ• āĻ¨ā§‡āĻŸāĻ“āĻ¯āĻŧāĻžāĻ°ā§āĻ• āĻļā§āĻ¨āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻ¯āĻĻāĻŋ āĻĒā§‹āĻ°ā§āĻŸ 80 āĻ†āĻĒāĻ¨āĻžāĻ° āĻŸā§‡āĻ¸ā§āĻŸ āĻšā§‹āĻ¸ā§āĻŸā§‡ āĻŦā§āĻ¯āĻ¸ā§āĻ¤ āĻĨāĻžāĻ•ā§‡, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻĒā§āĻ¯āĻžāĻ°āĻžāĻŽāĻŋāĻŸāĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§āĻ¨ --publish 80:80 āĻ‰āĻĒāĻ° --publish ANY_FREE_PORT:80.

āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ āĻ•ā§ŒāĻļāĻ˛

āĻĒā§āĻ°āĻŋāĻ¨ā§āĻŸāĻ†āĻ‰āĻŸ

$ 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>

āĻŦāĻŋāĻ°āĻžāĻŽāĻšā§€āĻ¨ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻž

āĻ†āĻ¸ā§āĻ¨ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ° āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖ āĻ°ā§‹āĻ˛ āĻ†āĻ‰āĻŸ āĻ•āĻ°āĻŋ (āĻāĻ•āĻŸāĻŋ āĻĻā§āĻŦāĻŋāĻ—ā§āĻŖ āĻ¸ā§āĻŸāĻžāĻ°ā§āĻŸāĻ†āĻĒ āĻĒāĻžāĻ°āĻĢāĻ°āĻŽā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻŦā§āĻ¸ā§āĻŸ āĻ¸āĻš) āĻāĻŦāĻ‚ āĻāĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻŦāĻŋāĻ˜ā§āĻ¨ā§‡ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻžāĻ° āĻšā§‡āĻˇā§āĻŸāĻž āĻ•āĻ°āĻŋāĨ¤

āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ āĻ•ā§ŒāĻļāĻ˛

  • echo 'my text' | docker exec -i my-container sh -c 'cat > /my-file.txt' - āĻĒāĻžāĻ ā§āĻ¯ āĻ˛āĻŋāĻ–ā§āĻ¨ my text āĻ¨āĻĨāĻŋāĻ¤ā§‡ /my-file.txt āĻĒāĻžāĻ¤ā§āĻ°ā§‡āĻ° āĻ­āĻŋāĻ¤āĻ°ā§‡ my-container.
  • cat > /my-file.txt — āĻāĻ•āĻŸāĻŋ āĻĢāĻžāĻ‡āĻ˛ā§‡ āĻ¸ā§āĻŸā§āĻ¯āĻžāĻ¨ā§āĻĄāĻžāĻ°ā§āĻĄ āĻ‡āĻ¨āĻĒā§āĻŸā§‡āĻ° āĻŦāĻŋāĻˇāĻ¯āĻŧāĻŦāĻ¸ā§āĻ¤ā§ āĻ˛āĻŋāĻ–ā§āĻ¨ /dev/stdin.

āĻĒā§āĻ°āĻŋāĻ¨ā§āĻŸāĻ†āĻ‰āĻŸ

$ 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

āĻāĻ‡ āĻĒāĻ°ā§āĻ¯āĻžāĻ¯āĻŧā§‡, āĻšāĻŋāĻ¤ā§āĻ°āĻŸāĻŋ āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ, āĻ¯āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ‰āĻ¤ā§āĻ¸āĻ—ā§āĻ˛āĻŋ āĻ¸ā§‡āĻ–āĻžāĻ¨ā§‡ āĻĨāĻžāĻ•āĻž āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻāĻŦāĻ‚ āĻ…āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻ•āĻžāĻœā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°āĻŸāĻŋ āĻ˛ā§‹āĻĄ āĻ•āĻ°ā§‡āĨ¤ āĻĒāĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻĒāĻĻāĻ•ā§āĻˇā§‡āĻĒāĻŸāĻŋ āĻšāĻ˛ āĻāĻ•āĻŸāĻŋ āĻĒā§ƒāĻĨāĻ• āĻŽā§‡āĻļāĻŋāĻ¨ā§‡ āĻ‡āĻŽā§‡āĻœ āĻ¸āĻŽāĻžāĻŦā§‡āĻļ āĻŦāĻ°āĻžāĻĻā§āĻĻ āĻ•āĻ°āĻž (āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻāĻ•āĻŸāĻŋ CI āĻ¸āĻŋāĻ¸ā§āĻŸā§‡āĻŽā§‡) āĻāĻŦāĻ‚ āĻ¤āĻžāĻ°āĻĒāĻ° āĻāĻŸāĻŋ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°āĻžāĨ¤

āĻ›āĻŦāĻŋ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ°

āĻĻā§āĻ°ā§āĻ­āĻžāĻ—ā§āĻ¯āĻŦāĻļāĻ¤, āĻ˛ā§‹āĻ•āĻžāĻ˛āĻšā§‹āĻ¸ā§āĻŸ āĻĨā§‡āĻ•ā§‡ āĻ˛ā§‹āĻ•āĻžāĻ˛āĻšā§‹āĻ¸ā§āĻŸā§‡ āĻ›āĻŦāĻŋ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°āĻžāĻ° āĻ•ā§‹āĻ¨ā§‹ āĻŽāĻžāĻ¨ā§‡ āĻšāĻ¯āĻŧ āĻ¨āĻž, āĻ¤āĻžāĻ‡ āĻāĻ‡ āĻŦāĻŋāĻ­āĻžāĻ—āĻŸāĻŋ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ¤āĻ–āĻ¨āĻ‡ āĻ…āĻ¨ā§āĻŦā§‡āĻˇāĻŖ āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ āĻ¯āĻĻāĻŋ āĻ†āĻĒāĻ¨āĻžāĻ° āĻšāĻžāĻ¤ā§‡ āĻĄāĻ•āĻžāĻ° āĻ¸āĻš āĻĻā§āĻŸāĻŋ āĻšā§‹āĻ¸ā§āĻŸ āĻĨāĻžāĻ•ā§‡āĨ¤ āĻ¸āĻ°ā§āĻŦāĻ¨āĻŋāĻŽā§āĻ¨ āĻāĻŸāĻŋ āĻāĻ‡ āĻŽāĻ¤ āĻ•āĻŋāĻ›ā§ āĻĻā§‡āĻ–āĻžāĻ¯āĻŧ:

$ 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

āĻŸā§€āĻŽ docker save āĻāĻ•āĻŸāĻŋ .tar āĻ†āĻ°ā§āĻ•āĻžāĻ‡āĻ­ā§‡ āĻ‡āĻŽā§‡āĻœ āĻĄā§‡āĻŸāĻž āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°ā§‡, āĻ¯āĻžāĻ° āĻ…āĻ°ā§āĻĨ āĻāĻŸāĻŋ āĻ¸āĻ‚āĻ•ā§āĻšāĻŋāĻ¤ āĻ†āĻ•āĻžāĻ°ā§‡ āĻ“āĻœāĻ¨ā§‡āĻ° āĻšā§‡āĻ¯āĻŧā§‡ āĻĒā§āĻ°āĻžāĻ¯āĻŧ 1.5 āĻ—ā§āĻŖ āĻŦā§‡āĻļāĻŋāĨ¤ āĻ¤āĻžāĻ‡ āĻ†āĻ¸ā§āĻ¨ āĻ¸āĻŽāĻ¯āĻŧ āĻāĻŦāĻ‚ āĻŸā§āĻ°āĻžāĻĢāĻŋāĻ• āĻ¸āĻžāĻļā§āĻ°āĻ¯āĻŧā§‡āĻ° āĻ¨āĻžāĻŽā§‡ āĻāĻŸāĻŋāĻ•ā§‡ āĻāĻžāĻāĻ•ā§āĻ¨āĻŋ āĻĻā§‡āĻ“āĻ¯āĻŧāĻž āĻ¯āĻžāĻ•:

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

āĻ†āĻĒāĻ¨āĻŋ āĻĄāĻžāĻ‰āĻ¨āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻžāĻ° āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻŸāĻŋāĻ“ āĻ¨āĻŋāĻ°ā§€āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ (āĻ¯āĻĻāĻŋāĻ“ āĻāĻŸāĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ¤ā§ƒāĻ¤ā§€āĻ¯āĻŧ āĻĒāĻ•ā§āĻˇā§‡āĻ° āĻ‡āĻ‰āĻŸāĻŋāĻ˛āĻŋāĻŸāĻŋ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨):

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

āĻŸāĻŋāĻĒ: SSH āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¯āĻĻāĻŋ āĻāĻ•āĻ—ā§āĻšā§āĻ› āĻĒā§āĻ¯āĻžāĻ°āĻžāĻŽāĻŋāĻŸāĻžāĻ°ā§‡āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻšāĻ¯āĻŧ, āĻ†āĻĒāĻ¨āĻŋ āĻĢāĻžāĻ‡āĻ˛āĻŸāĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ¨āĻžāĻ“ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ ~/.ssh/config.

āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ›āĻŦāĻŋ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡ docker image save/load - āĻāĻŸāĻŋ āĻ¸āĻŦāĻšā§‡āĻ¯āĻŧā§‡ āĻ¸āĻ‚āĻ•ā§āĻˇāĻŋāĻĒā§āĻ¤ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ, āĻ¤āĻŦā§‡ āĻāĻ•āĻŽāĻžāĻ¤ā§āĻ° āĻ¨āĻ¯āĻŧāĨ¤ āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻ†āĻ›ā§‡:

  1. āĻ•āĻ¨ā§āĻŸā§‡āĻ‡āĻ¨āĻžāĻ° āĻ°ā§‡āĻœāĻŋāĻ¸ā§āĻŸā§āĻ°āĻŋ (āĻļāĻŋāĻ˛ā§āĻĒ āĻŽāĻžāĻ¨)āĨ¤
  2. āĻ…āĻ¨ā§āĻ¯ āĻšā§‹āĻ¸ā§āĻŸ āĻĨā§‡āĻ•ā§‡ āĻĄāĻ•āĻžāĻ° āĻĄā§‡āĻŽāĻ¨ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨:
    1. āĻĒāĻ°āĻŋāĻŦā§‡āĻļ āĻ¸ā§‚āĻšāĻ• DOCKER_HOST.
    2. āĻ•āĻŽāĻžāĻ¨ā§āĻĄ āĻ˛āĻžāĻ‡āĻ¨ āĻŦāĻŋāĻ•āĻ˛ā§āĻĒ -H āĻŦāĻž --host āĻ¯āĻ¨ā§āĻ¤ā§āĻ° docker-compose.
    3. docker context

āĻĻā§āĻŦāĻŋāĻ¤ā§€āĻ¯āĻŧ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ (āĻāĻ° āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¤āĻŋāĻ¨āĻŸāĻŋ āĻŦāĻŋāĻ•āĻ˛ā§āĻĒ āĻ¸āĻš) āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§‡ āĻ­āĻžāĻ˛āĻ­āĻžāĻŦā§‡ āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡ āĻĄāĻ•āĻžāĻ°-āĻ•āĻŽā§āĻĒā§‹āĻœ āĻ¸āĻš āĻĻā§‚āĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻĄāĻ•āĻžāĻ° āĻšā§‹āĻ¸ā§āĻŸāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ•ā§€āĻ­āĻžāĻŦā§‡ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻŦā§‡āĻ¨.

deploy.sh

āĻāĻ–āĻ¨ āĻāĻ• āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸā§‡ āĻŽā§āĻ¯āĻžāĻ¨ā§āĻ¯āĻŧāĻžāĻ˛āĻŋ āĻ•āĻ°āĻž āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻ¸āĻ‚āĻ—ā§āĻ°āĻš āĻ•āĻ°āĻž āĻ¯āĻžāĻ•āĨ¤ āĻšāĻ˛ā§āĻ¨ āĻļā§āĻ°ā§ āĻ•āĻ°āĻž āĻ¯āĻžāĻ• āĻļā§€āĻ°ā§āĻˇ-āĻ¸ā§āĻ¤āĻ°ā§‡āĻ° āĻĢāĻžāĻ‚āĻļāĻ¨ āĻĻāĻŋāĻ¯āĻŧā§‡, āĻāĻŦāĻ‚ āĻ¤āĻžāĻ°āĻĒāĻ°ā§‡ āĻāĻ¤ā§‡ āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤ āĻ…āĻ¨ā§āĻ¯āĻ—ā§āĻ˛ā§‹ āĻĻā§‡āĻ–ā§āĻ¨āĨ¤

āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ āĻ•ā§ŒāĻļāĻ˛

  • ${parameter?err_msg} - āĻŦā§āĻ¯āĻžāĻļ āĻœāĻžāĻĻā§ āĻŽāĻ¨ā§āĻ¤ā§āĻ°āĻ—ā§āĻ˛āĻŋāĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻāĻ•āĻŸāĻŋ (āĻ“āĻ°āĻĢā§‡ āĻĒāĻ°āĻžāĻŽāĻŋāĻ¤āĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨)āĨ¤ āĻ¯āĻĻāĻŋ āĻāĻ•āĻŸāĻŋ parameter āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĻ¨āĻŋ, āĻ†āĻ‰āĻŸāĻĒā§āĻŸ err_msg āĻāĻŦāĻ‚ āĻ•ā§‹āĻĄ 1 āĻĻāĻŋāĻ¯āĻŧā§‡ āĻĒā§āĻ°āĻ¸ā§āĻĨāĻžāĻ¨ āĻ•āĻ°ā§āĻ¨āĨ¤
  • docker --log-driver journald — āĻĄāĻŋāĻĢāĻ˛ā§āĻŸāĻ°ā§‚āĻĒā§‡, āĻĄāĻ•āĻžāĻ° āĻ˛āĻ—āĻŋāĻ‚ āĻĄā§āĻ°āĻžāĻ‡āĻ­āĻžāĻ° āĻšāĻ˛ āĻ•ā§‹āĻ¨ā§‹ āĻ˜ā§‚āĻ°ā§āĻŖāĻ¨ āĻ›āĻžāĻĄāĻŧāĻžāĻ‡ āĻāĻ•āĻŸāĻŋ āĻĒāĻžāĻ ā§āĻ¯ āĻĢāĻžāĻ‡āĻ˛āĨ¤ āĻāĻ‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ā§‡, āĻ˛āĻ—āĻ—ā§āĻ˛āĻŋ āĻĻā§āĻ°ā§āĻ¤ āĻĒā§āĻ°ā§‹ āĻĄāĻŋāĻ¸ā§āĻ•āĻŸāĻŋ āĻĒā§‚āĻ°āĻŖ āĻ•āĻ°ā§‡, āĻ¤āĻžāĻ‡ āĻāĻ•āĻŸāĻŋ āĻ‰āĻ¤ā§āĻĒāĻžāĻĻāĻ¨ āĻĒāĻ°āĻŋāĻŦā§‡āĻļā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĄā§āĻ°āĻžāĻ‡āĻ­āĻžāĻ°āĻŸāĻŋāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻŦā§āĻĻā§āĻ§āĻŋāĻŽāĻžāĻ¨ā§‡ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻž āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨āĨ¤

āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻžāĻ° āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ

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
}

āĻŦā§āĻ¯āĻŦāĻšā§ƒāĻ¤ āĻŦā§ˆāĻļāĻŋāĻˇā§āĻŸā§āĻ¯:

  • ensure-reverse-proxy - āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨ āĻ¯ā§‡ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ•āĻžāĻœ āĻ•āĻ°āĻ›ā§‡ (āĻĒā§āĻ°āĻĨāĻŽ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻĻāĻ°āĻ•āĻžāĻ°ā§€)
  • get-active-slot service_name — āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ°āĻĻāĻ¤ā§āĻ¤ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ā§‡ āĻ•ā§‹āĻ¨ āĻ¸ā§āĻ˛āĻŸ āĻ¸āĻ•ā§āĻ°āĻŋāĻ¯āĻŧ āĻ¤āĻž āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŖ āĻ•āĻ°ā§‡ (BLUE āĻŦāĻž GREEN)
  • get-service-status service_name deployment_slot - āĻ†āĻ—āĻ¤ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ—ā§āĻ˛āĻŋ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻĒā§āĻ°āĻ¸ā§āĻ¤ā§āĻ¤ āĻ•āĻŋāĻ¨āĻž āĻ¤āĻž āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŖ āĻ•āĻ°ā§‡
  • set-active-slot service_name deployment_slot - āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋ āĻ•āĻ¨ā§āĻŸā§‡āĻ‡āĻ¨āĻžāĻ°ā§‡ nginx āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§‡

āĻ•ā§āĻ°āĻŽ:

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
}

āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž get-active-slot āĻāĻ•āĻŸā§ āĻŦā§āĻ¯āĻžāĻ–ā§āĻ¯āĻž āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨:

āĻ•ā§‡āĻ¨ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž āĻĢā§‡āĻ°āĻ¤ āĻĻā§‡āĻ¯āĻŧ āĻāĻŦāĻ‚ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻŸā§āĻ°āĻŋāĻ‚ āĻ†āĻ‰āĻŸāĻĒā§āĻŸ āĻ¨āĻž?

āĻ¯āĻžāĻ‡āĻšā§‹āĻ•, āĻ•āĻ˛āĻŋāĻ‚ āĻĢāĻžāĻ‚āĻļāĻ¨ā§‡ āĻ†āĻŽāĻ°āĻž āĻāĻ° āĻ•āĻžāĻœā§‡āĻ° āĻĢāĻ˛āĻžāĻĢāĻ˛ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻŦā§āĻ¯āĻžāĻļ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻāĻ•ā§āĻ¸āĻŋāĻŸ āĻ•ā§‹āĻĄ āĻšā§‡āĻ• āĻ•āĻ°āĻž āĻ¸ā§āĻŸā§āĻ°āĻŋāĻ‚ āĻšā§‡āĻ• āĻ•āĻ°āĻžāĻ° āĻšā§‡āĻ¯āĻŧā§‡ āĻ…āĻ¨ā§‡āĻ• āĻ¸āĻšāĻœāĨ¤ āĻ‰āĻĒāĻ°āĻ¨ā§āĻ¤ā§, āĻāĻŸāĻŋ āĻĨā§‡āĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻŸā§āĻ°āĻŋāĻ‚ āĻĒāĻžāĻ“āĻ¯āĻŧāĻž āĻ–ā§āĻŦ āĻ¸āĻšāĻœ:
get-active-slot service && echo BLUE || echo GREEN.

āĻ¤āĻŋāĻ¨āĻŸāĻŋ āĻļāĻ°ā§āĻ¤ āĻ•āĻŋ āĻ¸āĻ¤ā§āĻ¯āĻŋāĻ‡ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ°āĻžāĻœā§āĻ¯āĻ•ā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ¯āĻĨā§‡āĻˇā§āĻŸ?

āĻ¨ā§āĻ¯ā§‚āĻ¨āĻ¤āĻŽ āĻŽāĻœā§āĻ°āĻŋāĻ¤ā§‡ āĻ¨ā§€āĻ˛-āĻ¸āĻŦā§āĻœ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻž

āĻāĻŽāĻ¨āĻ•āĻŋ āĻĻā§āĻŸāĻŋ āĻ¯āĻĨā§‡āĻˇā§āĻŸ āĻšāĻŦā§‡, āĻļā§‡āĻˇāĻŸāĻŋ āĻāĻ–āĻžāĻ¨ā§‡ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖāĻ¤āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¯āĻžāĻ¤ā§‡ āĻ˛āĻŋāĻ–āĻ¤ā§‡ āĻ¨āĻž āĻšāĻ¯āĻŧ else.

āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ¯ā§‡ āĻĢāĻžāĻ‚āĻļāĻ¨āĻŸāĻŋ nginx āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°ā§‡ āĻ¤āĻž āĻ…āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŋāĻ¤ āĻĨāĻžāĻ•ā§‡: get-nginx-config service_name deployment_slot. āĻ¸ā§āĻŦāĻžāĻ¸ā§āĻĨā§āĻ¯ āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻžāĻĻā§ƒāĻļā§āĻ¯ āĻĻā§āĻŦāĻžāĻ°āĻž, āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ¯ā§‡ āĻ•ā§‹āĻ¨āĻ“ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ¯ā§‡ āĻ•ā§‹āĻ¨āĻ“ āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ āĻ¸ā§‡āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤ āĻ†āĻ•āĻ°ā§āĻˇāĻŖā§€āĻ¯āĻŧ āĻœāĻŋāĻ¨āĻŋāĻ¸ - āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° cat <<- EOF, āĻ¯āĻž āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻļā§āĻ°ā§āĻ¤ā§‡ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻŸā§āĻ¯āĻžāĻŦ āĻ¸āĻ°āĻžāĻ¤ā§‡ āĻĻā§‡āĻ¯āĻŧāĨ¤ āĻ¸āĻ¤ā§āĻ¯, āĻ­āĻžāĻ˛ āĻŦāĻŋāĻ¨ā§āĻ¯āĻžāĻ¸ā§‡āĻ° āĻŽā§‚āĻ˛ā§āĻ¯ āĻšāĻ˛ āĻ¸ā§āĻĒā§‡āĻ¸ āĻ¸āĻš āĻŽāĻŋāĻļā§āĻ° āĻŸā§āĻ¯āĻžāĻŦ, āĻ¯āĻž āĻ†āĻœāĻ•ā§‡ āĻ–ā§āĻŦ āĻ–āĻžāĻ°āĻžāĻĒ āĻĢāĻ°ā§āĻŽ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻŦāĻŋāĻŦā§‡āĻšāĻŋāĻ¤ āĻšāĻ¯āĻŧāĨ¤ āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻŦā§āĻ¯āĻžāĻļ āĻŸā§āĻ¯āĻžāĻŦāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻœā§‹āĻ° āĻ•āĻ°ā§‡, āĻāĻŦāĻ‚ nginx āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ā§‡ āĻ¸ā§āĻŦāĻžāĻ­āĻžāĻŦāĻŋāĻ• āĻŦāĻŋāĻ¨ā§āĻ¯āĻžāĻ¸ āĻ•āĻ°āĻžāĻ“ āĻ­āĻžāĻ˛ āĻšāĻŦā§‡āĨ¤ āĻ¸āĻ‚āĻ•ā§āĻˇā§‡āĻĒā§‡, āĻāĻ–āĻžāĻ¨ā§‡ āĻ¸ā§āĻĒā§‡āĻ¸āĻ—ā§āĻ˛āĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻŸā§āĻ¯āĻžāĻŦāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻŽāĻŋāĻļā§āĻ°āĻŋāĻ¤ āĻ•āĻ°āĻž āĻ¸āĻ¤ā§āĻ¯āĻŋāĻ‡ āĻ–āĻžāĻ°āĻžāĻĒā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ¸ā§‡āĻ°āĻž āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻŦāĻ˛ā§‡ āĻŽāĻ¨ā§‡ āĻšāĻšā§āĻ›ā§‡āĨ¤ āĻ¯āĻžāĻ‡āĻšā§‹āĻ•, āĻ†āĻĒāĻ¨āĻŋ āĻ¨ā§€āĻšā§‡āĻ° āĻ¸ā§āĻ¨āĻŋāĻĒā§‡āĻŸā§‡ āĻāĻŸāĻŋ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻĒāĻžāĻŦā§‡āĻ¨ āĻ¨āĻž, āĻ¯ā§‡āĻšā§‡āĻ¤ā§ Habr āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻŸā§āĻ¯āĻžāĻŦāĻ—ā§āĻ˛āĻŋāĻ•ā§‡ 4āĻŸāĻŋ āĻ¸ā§āĻĒā§‡āĻ¸ā§‡ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ EOF āĻ…āĻŦā§ˆāĻ§ āĻ•āĻ°ā§‡ "āĻāĻŸāĻŋ āĻ­āĻžāĻ˛ āĻ•āĻ°ā§‡"āĨ¤ āĻāĻŦāĻ‚ āĻāĻ–āĻžāĻ¨ā§‡ āĻāĻŸāĻŋ āĻ˛āĻ•ā§āĻˇāĻŖā§€āĻ¯āĻŧ.

āĻ¯āĻžāĻ¤ā§‡ āĻĻā§āĻŦāĻžāĻ° āĻ‰āĻ āĻ¤ā§‡ āĻ¨āĻž āĻšāĻ¯āĻŧ, āĻ†āĻŽāĻŋ āĻāĻ–āĻ¨āĻ‡ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻŦāĻ˛āĻŦ cat << 'EOF', āĻ¯āĻž āĻĒāĻ°ā§‡ āĻ¸āĻŽā§āĻŽā§āĻ–ā§€āĻ¨ āĻšāĻŦā§‡. āĻ¸āĻšāĻœāĻ­āĻžāĻŦā§‡ āĻ˛āĻŋāĻ–āĻ˛ā§‡ cat << EOF, āĻ¤āĻžāĻ°āĻĒāĻ° heredoc āĻāĻ° āĻ­āĻŋāĻ¤āĻ°ā§‡ āĻ¸ā§āĻŸā§āĻ°āĻŋāĻ‚āĻŸāĻŋ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĒā§‹āĻ˛ā§‡āĻŸ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ (āĻ­ā§‡āĻ°āĻŋāĻ¯āĻŧā§‡āĻŦāĻ˛āĻ—ā§āĻ˛āĻŋ āĻĒā§āĻ°āĻ¸āĻžāĻ°āĻŋāĻ¤ āĻšāĻ¯āĻŧ ($foo), āĻ•āĻŽāĻžāĻ¨ā§āĻĄ āĻ•āĻ˛ ($(bar)) āĻ‡āĻ¤ā§āĻ¯āĻžāĻĻāĻŋ), āĻāĻŦāĻ‚ āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻ¨āĻĨāĻŋāĻ° āĻļā§‡āĻˇāĻŸāĻŋ āĻāĻ•āĻ• āĻ‰āĻĻā§āĻ§ā§ƒāĻ¤āĻŋāĻ¤ā§‡ āĻ†āĻŦāĻĻā§āĻ§ āĻ•āĻ°ā§‡āĻ¨, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĒā§‹āĻ˛ā§‡āĻļāĻ¨ āĻ…āĻ•ā§āĻˇāĻŽ āĻāĻŦāĻ‚ āĻĒā§āĻ°āĻ¤ā§€āĻ• $ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻŋāĻ¤ āĻšāĻ¯āĻŧ. āĻ†āĻĒāĻ¨āĻŋ āĻ…āĻ¨ā§āĻ¯ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ­āĻŋāĻ¤āĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ¸āĻ¨ā§āĻ¨āĻŋāĻŦā§‡āĻļ āĻ•āĻ°āĻž āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻ•āĻŋ.

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
}

āĻāĻŸāĻŋ āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĨ¤ āĻāĻŦāĻ‚ āĻ¤āĻžāĻ‡ āĻāĻ‡ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ¸āĻ™ā§āĻ—ā§‡ āĻ¸āĻžāĻ°āĻžāĻ‚āĻļ wget āĻŦāĻž curl āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻĄāĻžāĻ‰āĻ¨āĻ˛ā§‹āĻĄ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯āĨ¤

āĻĻā§‚āĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻĒā§āĻ¯āĻžāĻ°āĻžāĻŽāĻŋāĻŸāĻžāĻ°āĻžāĻ‡āĻœāĻĄ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻšāĻžāĻ˛āĻžāĻ¨ā§‹ āĻšāĻšā§āĻ›ā§‡

āĻ˛āĻ•ā§āĻˇā§āĻ¯ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻ¨āĻ• āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻāĻ¸ā§‡āĻ›ā§‡āĨ¤ āĻāĻ‡āĻŦāĻžāĻ° localhost āĻŦā§‡āĻļ āĻ‰āĻĒāĻ¯ā§āĻ•ā§āĻ¤:

$ 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.

āĻ†āĻŽāĻ°āĻž āĻāĻ•āĻŸāĻŋ āĻ¸ā§āĻĨāĻžāĻĒāĻ¨āĻžāĻ° āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ˛āĻŋāĻ–ā§‡āĻ›āĻŋ āĻ¯āĻž āĻ˛āĻ•ā§āĻˇā§āĻ¯ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻĒā§‚āĻ°ā§āĻŦ-āĻ¨āĻŋāĻ°ā§āĻŽāĻŋāĻ¤ āĻšāĻŋāĻ¤ā§āĻ° āĻĄāĻžāĻ‰āĻ¨āĻ˛ā§‹āĻĄ āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻ¨āĻŋāĻ°ā§āĻŦāĻŋāĻ˜ā§āĻ¨ā§‡ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻ§āĻžāĻ°āĻ•āĻŸāĻŋ āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°ā§‡, āĻ¤āĻŦā§‡ āĻ†āĻŽāĻ°āĻž āĻ•ā§€āĻ­āĻžāĻŦā§‡ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻĻā§‚āĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻŽā§‡āĻļāĻŋāĻ¨ā§‡ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ? āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻŸāĻŋāĻ¤ā§‡ āĻ¯ā§āĻ•ā§āĻ¤āĻŋ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻāĻŸāĻŋ āĻ¸āĻ°ā§āĻŦāĻœāĻ¨ā§€āĻ¨ āĻāĻŦāĻ‚ āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻĒāĻ°ā§€āĻ¤ āĻĒā§āĻ°āĻ•ā§āĻ¸āĻŋāĻ° āĻ…āĻ§ā§€āĻ¨ā§‡ āĻāĻ•āĻ¸āĻžāĻĨā§‡ āĻŦā§‡āĻļ āĻ•āĻ¯āĻŧā§‡āĻ•āĻŸāĻŋ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ (āĻ•ā§‹āĻ¨ url āĻ•ā§‹āĻ¨ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻšāĻŦā§‡ āĻ¤āĻž āĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŖ āĻ•āĻ°āĻ¤ā§‡ āĻ†āĻĒāĻ¨āĻŋ nginx āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨)āĨ¤ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻŸāĻŋ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž āĻ¯āĻžāĻŦā§‡ āĻ¨āĻž, āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻāĻ‡ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ āĻ†āĻŽāĻ°āĻž āĻāĻŸāĻŋ āĻ¸ā§āĻŦāĻ¯āĻŧāĻ‚āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻ­āĻžāĻŦā§‡ āĻ†āĻĒāĻĄā§‡āĻŸ āĻ•āĻ°āĻ¤ā§‡ āĻ¸āĻ•ā§āĻˇāĻŽ āĻšāĻŦ āĻ¨āĻž (āĻŦāĻžāĻ— āĻ¸āĻ‚āĻļā§‹āĻ§āĻ¨ āĻāĻŦāĻ‚ āĻ¨āĻ¤ā§āĻ¨ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻ¯ā§‹āĻ— āĻ•āĻ°āĻžāĻ° āĻ‰āĻĻā§āĻĻā§‡āĻļā§āĻ¯ā§‡), āĻāĻŦāĻ‚ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖāĻ­āĻžāĻŦā§‡, āĻ°āĻžāĻˇā§āĻŸā§āĻ° = āĻ–āĻžāĻ°āĻžāĻĒāĨ¤

āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ 1: āĻāĻ–āĻ¨āĻ“ āĻ¸āĻžāĻ°ā§āĻ­āĻžāĻ°ā§‡ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°ā§āĻ¨, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻĒā§āĻ°āĻ¤āĻŋāĻŦāĻžāĻ° āĻāĻŸāĻŋ āĻ…āĻ¨ā§āĻ˛āĻŋāĻĒāĻŋ āĻ•āĻ°ā§āĻ¨ scp. āĻ¤āĻžāĻ°āĻĒāĻ° āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ¸āĻ‚āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨ ssh āĻāĻŦāĻ‚ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻ†āĻ°ā§āĻ—ā§āĻŽā§‡āĻ¨ā§āĻŸ āĻ¸āĻš āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻŸāĻŋ āĻšāĻžāĻ˛āĻžāĻ¨āĨ¤

āĻ•āĻ¨āĻ¸:

  • āĻāĻ•āĻŸāĻŋāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§‡ āĻĻā§āĻŸāĻŋ āĻ•āĻ°ā§āĻŽ
  • āĻāĻŽāĻ¨ āĻāĻ•āĻŸāĻŋ āĻœāĻžāĻ¯āĻŧāĻ—āĻž āĻ¨āĻžāĻ“ āĻĨāĻžāĻ•āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻĒāĻŋ āĻ•āĻ°ā§‡āĻ¨, āĻŦāĻž āĻ¸ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ…ā§āĻ¯āĻžāĻ•ā§āĻ¸ā§‡āĻ¸ āĻ¨āĻžāĻ“ āĻĨāĻžāĻ•āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡, āĻŦāĻž āĻĒā§āĻ°āĻ¤āĻŋāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ā§‡āĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻŸāĻŋ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻž āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤
  • āĻ¨āĻŋāĻœā§‡āĻ° āĻĒāĻ°ā§‡ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°āĻžāĻ° āĻĒāĻ°āĻžāĻŽāĻ°ā§āĻļ āĻĻā§‡āĻ“āĻ¯āĻŧāĻž āĻšāĻ¯āĻŧ (āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸāĻŸāĻŋ āĻŽā§āĻ›ā§āĻ¨)āĨ¤
  • āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡ āĻ¤āĻŋāĻ¨āĻŸāĻŋ āĻ•āĻ°ā§āĻŽāĨ¤

āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ 2:

  • āĻ¸ā§āĻ•ā§āĻ°āĻŋāĻĒā§āĻŸā§‡ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻĢāĻžāĻ‚āĻļāĻ¨ āĻ¸āĻ‚āĻœā§āĻžāĻž āĻ°āĻžāĻ–ā§āĻ¨ āĻāĻŦāĻ‚ āĻ•āĻŋāĻ›ā§āĻ‡ āĻšāĻžāĻ˛āĻžāĻŦā§‡āĻ¨ āĻ¨āĻž
  • āĻāĻ° āĻ¸āĻžāĻšāĻžāĻ¯ā§āĻ¯ā§‡ sed āĻļā§‡āĻˇā§‡ āĻāĻ•āĻŸāĻŋ āĻĢāĻžāĻ‚āĻļāĻ¨ āĻ•āĻ˛ āĻ¯ā§‹āĻ— āĻ•āĻ°ā§āĻ¨
  • āĻĒāĻžāĻ‡āĻĒā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ¸āĻ°āĻžāĻ¸āĻ°āĻŋ shh āĻ āĻ¸āĻŦ āĻĒāĻžāĻ āĻžāĻ¨ (|)

āĻĒā§‡āĻļāĻžāĻĻāĻžāĻ°āĻ°āĻž:

  • āĻ¸āĻ¤ā§āĻ¯āĻŋāĻ‡ āĻ°āĻžāĻˇā§āĻŸā§āĻ°āĻšā§€āĻ¨
  • āĻ•ā§‹āĻ¨ā§‹ āĻŦāĻ¯āĻŧāĻ˛āĻžāĻ°āĻĒā§āĻ˛ā§‡āĻŸ āĻ¸āĻ¤ā§āĻ¤āĻž āĻ¨ā§‡āĻ‡
  • āĻ āĻžāĻŖā§āĻĄāĻž āĻ˛āĻžāĻ—āĻ›ā§‡

āĻāĻ° āĻ‰āĻ¤ā§āĻ¤āĻ° āĻ›āĻžāĻĄāĻŧāĻžāĻ‡ āĻāĻŸāĻŋ āĻ•āĻ°āĻž āĻ¯āĻžāĻ•āĨ¤ āĻšā§āĻ¯āĻžāĻ, āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡ āĻ‰āĻĻā§āĻ­āĻžāĻŦāĻŋāĻ¤ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ āĻšā§āĻ¯āĻžāĻ, āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻ‡āĻ•ā§‡āĻ˛āĨ¤ āĻŦāĻžāĻ‡āĻ•āĻŸāĻŋ āĻ•āĻ¤āĻŸāĻž āĻ¸āĻšāĻœ, āĻŽāĻžāĻ°ā§āĻœāĻŋāĻ¤ āĻāĻŦāĻ‚ āĻŽāĻŋāĻ¨āĻŋāĻŽāĻžāĻ˛āĻŋāĻ¸ā§āĻŸāĻŋāĻ• āĻ¤āĻž āĻĻā§‡āĻ–ā§āĻ¨:

$ 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'

āĻ¯āĻžāĻ‡āĻšā§‹āĻ•, āĻ†āĻŽāĻ°āĻž āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ āĻ¨āĻž āĻ¯ā§‡ āĻĻā§‚āĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻšā§‹āĻ¸ā§āĻŸā§‡āĻ° āĻĒāĻ°ā§āĻ¯āĻžāĻĒā§āĻ¤ āĻŦā§āĻ¯āĻžāĻļ āĻ†āĻ›ā§‡, āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻ°āĻž āĻļā§āĻ°ā§āĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻ›ā§‹āĻŸ āĻšā§‡āĻ• āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŦ (āĻāĻŸāĻŋ āĻāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤ā§‡ āĻļā§‡āĻ˛āĻŦā§āĻ¯āĻžāĻ‚):

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

āĻāĻŦāĻ‚ āĻāĻ–āĻ¨ āĻāĻŸāĻŋ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦ:

$ 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!

āĻāĻ–āĻ¨ āĻ†āĻĒāĻ¨āĻŋ āĻ–ā§āĻ˛āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ http://localhost/ āĻŦā§āĻ°āĻžāĻ‰āĻœāĻžāĻ°ā§‡, āĻĄāĻŋāĻĒā§āĻ˛āĻ¯āĻŧāĻŽā§‡āĻ¨ā§āĻŸāĻŸāĻŋ āĻ†āĻŦāĻžāĻ° āĻšāĻžāĻ˛āĻžāĻ¨ āĻāĻŦāĻ‚ āĻ˛ā§‡āĻ†āĻ‰āĻŸā§‡āĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ¸āĻŋāĻĄāĻŋ āĻ…āĻ¨ā§āĻ¯āĻžāĻ¯āĻŧā§€ āĻĒā§ƒāĻˇā§āĻ āĻž āĻ†āĻĒāĻĄā§‡āĻŸ āĻ•āĻ°ā§‡ āĻāĻŸāĻŋ āĻ¨āĻŋāĻ°ā§āĻŦāĻŋāĻ˜ā§āĻ¨ā§‡ āĻšāĻ˛ā§‡ āĻ•āĻŋāĻ¨āĻž āĻ¤āĻž āĻ¨āĻŋāĻļā§āĻšāĻŋāĻ¤ āĻ•āĻ°ā§āĻ¨āĨ¤

āĻ•āĻžāĻœā§‡āĻ° āĻĒāĻ°ā§‡ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻ­ā§āĻ˛āĻŦā§‡āĻ¨ āĻ¨āĻž :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

āĻ‰āĻ¤ā§āĻ¸: www.habr.com