በሚሊዮኖች የሚቆጠሩ የፊት-መጨረሻ መተግበሪያዎች አካባቢ-ተኮር ግንባታዎችን በማስተዳደር ላይ ናቸው። ለእያንዳንዱ አካባቢ - ልማት፣ ዝግጅት ወይም ምርት ቢሆን - የፊት ለፊት መተግበሪያ የተለየ ግንባታ መፈጠር አለበት እና ትክክለኛ የአካባቢ ተለዋዋጮች መዘጋጀት አለባቸው። ብዙ አፕሊኬሽኖች ከተሳተፉ የግንባታዎች ቁጥር ይባዛል፣ ይህም ወደ ብስጭት ይጨምራል። ይህ ለረጅም ጊዜ የተለመደ ችግር ነው፣ ነገር ግን የአካባቢ ተለዋዋጮችን ለመቆጣጠር የተሻለ መንገድ አለ። ይህንን ሂደት ለማሳለጥ መንገድ አግኝቻለሁ፣ እና በዚህ ጽሑፍ ውስጥ፣ የግንባታ ጊዜዎችን የሚቀንስ እና በፕሮጀክቶችዎ ውስጥ ያሉ አከባቢዎች ወጥነት እንዲኖራቸው የሚያግዝ ቀልጣፋ ሂደት ለመፍጠር ደረጃ በደረጃ እመራችኋለሁ።
ከመጀመራችን በፊት፣ ሪክፕ ማድረግ ያለብን ይመስለኛል። የድረ-ገጽ አፕሊኬሽኖች ሁልጊዜ ማለት ይቻላል "የአካባቢ ተለዋዋጮች " በመባል በሚታወቁት ተለዋዋጮች ላይ ይተማመናሉ፣ እነዚህም ብዙውን ጊዜ የውስጥ ስርዓት የመጨረሻ ነጥቦችን፣ የውህደት ስርዓቶችን፣ የክፍያ ስርዓት ቁልፎችን፣ የመልቀቂያ ቁጥሮችን እና የመሳሰሉትን ያካትታሉ። በተፈጥሮ፣ የእነዚህ ተለዋዋጮች እሴቶች አፕሊኬሽኑ በተሰማራበት አካባቢ ላይ በመመስረት ይለያያሉ።
ለምሳሌ፣ ከክፍያ መግቢያ በር ጋር የሚገናኝ መተግበሪያን አስቡት። በልማት አካባቢ፣ የክፍያ መግቢያው ዩአርኤል ለሙከራ ማጠሪያ (https://sandbox.paymentgateway.com) ሊያመለክት ይችላል፣ በምርት አካባቢ ደግሞ የቀጥታ አገልግሎቱን ይጠቁማል (https://live.paymentgateway.com) ). በተመሳሳይ፣ የውሂብ ደህንነትን ለማረጋገጥ እና አካባቢዎችን እንዳይቀላቀሉ ለማድረግ የተለያዩ የኤፒአይ ቁልፎች ወይም ማንኛውም ሌላ አካባቢ ተኮር መቼት ጥቅም ላይ ይውላሉ።
የኋላ ትግበራዎችን በሚገነቡበት ጊዜ, ይህ ችግር አይደለም. የእነዚህ ተለዋዋጮች እሴቶች የጀርባው በተዘረጋበት የአገልጋይ አካባቢ ስለሚቀመጡ እነዚህን ተለዋዋጮች በመተግበሪያ ኮድ ውስጥ ማወጅ በቂ ነው። በዚህ መንገድ የኋለኛው መተግበሪያ ጅምር ላይ ይደርስባቸዋል።
ነገር ግን፣ ከግንባር አፕሊኬሽኖች ጋር ነገሮች በተወሰነ ደረጃ ውስብስብ ይሆናሉ። የሚሄዱት በተጠቃሚው አሳሽ ስለሆነ የተወሰኑ የአካባቢ ተለዋዋጭ እሴቶችን ማግኘት አይችሉም። ይህንን ለመቅረፍ የነዚህ ተለዋዋጮች እሴቶች በግንባታ ጊዜ በተለምዶ "ወደ ፊት ለፊት" መተግበሪያ ይጋገራሉ። በዚህ መንገድ አፕሊኬሽኑ በተጠቃሚው አሳሽ ውስጥ ሲሰራ ሁሉም አስፈላጊ እሴቶች በፊተኛው ትግበራ ውስጥ ገብተዋል።
ይህ አካሄድ፣ ልክ እንደሌሎች ብዙ፣ ከማሳሰቢያ ጋር አብሮ ይመጣል፡ እያንዳንዱ ግንባታ የራሱ የሆኑ እሴቶችን እንዲይዝ ለእያንዳንዱ አካባቢ ተመሳሳይ የፊት ለፊት መተግበሪያ የተለየ ግንባታ መፍጠር ያስፈልግዎታል።
ለምሳሌ ሶስት አከባቢዎች አሉን እንበል፡-
ለውስጣዊ ምርመራ እድገት;
የውህደት ሙከራ ደረጃ;
እና ለደንበኞች ምርት.
ስራዎን ለሙከራ ለማስገባት መተግበሪያውን ገንብተው ወደ ልማት አካባቢ ያሰማሩታል። የውስጥ ሙከራ ከተጠናቀቀ በኋላ መተግበሪያውን ወደ መድረክ ለማሰማራት እና ወደ ምርት ለማሰማራት እንደገና መገንባት ያስፈልግዎታል። ፕሮጀክቱ ከአንድ በላይ የፊት-መጨረሻ መተግበሪያን ከያዘ, የእንደዚህ አይነት ግንባታዎች ቁጥር በከፍተኛ ሁኔታ ይጨምራል. በተጨማሪም፣ በእነዚህ ግንባታዎች መካከል፣ ኮድ ቤዝ አይቀየርም - ሁለተኛው እና ሦስተኛው ግንባታዎች በተመሳሳይ የምንጭ ኮድ ላይ የተመሰረቱ ናቸው።
ይህ ሁሉ የመልቀቂያ ሂደቱን ግዙፍ, ቀርፋፋ እና ውድ ያደርገዋል, እንዲሁም የጥራት ማረጋገጫ አደጋን ያመጣል. ምናልባት ግንባታው በልማት አካባቢ በደንብ የተሞከረ ሊሆን ይችላል፣ ነገር ግን የመድረክ ግንባታው በቴክኒካል አዲስ ነው፣ ይህም ማለት አሁን አዲስ የስህተት እምቅ አቅም አለ።
ምሳሌ፡- ሁለት አፕሊኬሽኖች የ X እና Y ሰከንድ ጊዜዎች አሉዎት። ለእነዚያ ሶስት አካባቢዎች ሁለቱም መተግበሪያዎች በግንባታ ጊዜ 3X + 3Y ይወስዳሉ። ነገር ግን፣ እያንዳንዱን መተግበሪያ አንድ ጊዜ ብቻ መገንባት ከቻሉ እና ተመሳሳይ ግንባታን በሁሉም አካባቢዎች መጠቀም ከቻሉ አጠቃላይ ሰዓቱ ወደ X + Y ሰከንድ ብቻ ይቀንሳል፣ ይህም የግንባታ ጊዜውን በሶስት እጥፍ ይቀንሳል።
ይህ በግንባር ቀደምት የቧንቧ መስመሮች ላይ ትልቅ ለውጥ ሊያመጣ ይችላል፣ ግብዓቶች የተገደቡ እና የግንባታ ጊዜዎች ከጥቂት ደቂቃዎች እስከ ከአንድ ሰአት በላይ ሊደርሱ ይችላሉ። ጉዳዩ በአለምአቀፍ ደረጃ በሁሉም የፊትለፊት አፕሊኬሽኖች ውስጥ አለ፣ እና ብዙውን ጊዜ እሱን ለመፍታት ምንም መንገድ የለም። ሆኖም፣ ይህ ከባድ ችግር ነው፣ በተለይ ከንግድ አንፃር።
ሶስት የተለያዩ ግንባታዎችን ከመፍጠር ይልቅ አንድ ብቻ ሠርተህ በሁሉም አካባቢዎች ብታሰማራ ጥሩ አይሆንም? ደህና፣ በትክክል ያንን ለማድረግ የሚያስችል መንገድ አግኝቻለሁ።
የአካባቢ ተለዋዋጮችን ማዘጋጀት
በመጀመሪያ፣ የሚፈለጉት የአካባቢ ተለዋዋጮች የሚዘረዘሩበት በFrontend ፕሮጀክትዎ ማከማቻ ውስጥ ፋይል መፍጠር ያስፈልግዎታል። እነዚህ በአገር ውስጥ በገንቢው ጥቅም ላይ ይውላሉ። በተለምዶ ይህ ፋይል .env.local
ተብሎ ይጠራል፣ ይህም አብዛኞቹ ዘመናዊ የፊት ለፊት ማዕቀፎች ማንበብ ይችላሉ። የእንደዚህ አይነት ፋይል ምሳሌ ይኸውና
CLIENT_ID='frontend-development' API_URL=/api/v1' PUBLIC_URL='/' COMMIT_SHA=''
ማሳሰቢያ፡- የተለያዩ ማዕቀፎች ለአካባቢ ተለዋዋጮች የተለያዩ የመጠሪያ ስምምነቶችን ይፈልጋሉ። ለምሳሌ፣ በReact ውስጥ፣ REACT_APP_
ከተለዋዋጭ ስሞች ጋር አስቀድመው ማዘጋጀት ያስፈልግዎታል። ይህ ፋይል የግድ በመተግበሪያው ላይ ተጽዕኖ የሚያሳድሩ ተለዋዋጮችን ማካተት አያስፈልገውም። ጠቃሚ የማረም መረጃን ሊይዝ ይችላል። የ COMMIT_SHA
ተለዋዋጭ ጨምሬአለሁ፣ በኋላም ከግንባታው ስራ የምንጎትተው ይህ ግንባታ የተመሰረተበትን ቁርጠኝነት ለመከታተል ነው።
በመቀጠል environment.js
የሚጠራውን ፋይል ይፍጠሩ.js, የትኛውን የአካባቢ ተለዋዋጮች እንደሚፈልጉ መወሰን ይችላሉ. የፊት ለፊት ማዕቀፍ እነዚህን ለእርስዎ ያስገባልዎታል. ለ React፣ ለምሳሌ፣ በ process.env
ነገር ውስጥ ተከማችተዋል፡-
const ORIGIN_ENVIRONMENTS = window.ORIGIN_ENVIRONMENTS = { CLIENT_ID: process.env.CLIENT_ID, API_URL: process.env.API_URL, PUBLIC_URL: process.env.PUBLIC_URL, COMMIT_SHA: process.env.COMMIT_SHA }; export const ENVIRONMENT = { clientId: ORIGIN_ENVIRONMENTS.CLIENT_ID, apiUrl: ORIGIN_ENVIRONMENTS.API_URL, publicUrl: ORIGIN_ENVIRONMENTS.PUBLIC_URL ?? "/", commitSha: ORIGIN_ENVIRONMENTS.COMMIT_SHA, };
እዚህ፣ window.ORIGIN_ENVIRONMENTS
ውስጥ ለተለዋዋጮች ሁሉንም የመጀመሪያ ዋጋዎችን ሰርስረሃል።ORIGIN_ENVIRONMENTS ነገር፣ይህም በአሳሹ መሥሪያው ውስጥ እንድትመለከቷቸው ይፈቅድልሃል። በተጨማሪም ፣ እነሱን ወደ ENVIRONMENT
ነገር መቅዳት ያስፈልግዎታል ፣ እዚያም አንዳንድ ነባሪዎችን ማዘጋጀት ይችላሉ ፣ ለምሳሌ publicUrl
በነባሪ ነው ብለን እንገምታለን። በመተግበሪያው ውስጥ እነዚህ ተለዋዋጮች በሚያስፈልጉበት ቦታ ሁሉ ENVIRONMENT
ነገር ይጠቀሙ።
በዚህ ደረጃ፣ ሁሉንም የአካባቢ ልማት ፍላጎቶች አሟልተዋል። ነገር ግን ግቡ የተለያዩ አካባቢዎችን ማስተናገድ ነው.
ይህንን ለማድረግ፣ በሚከተለው ይዘት .env
ፋይል ይፍጠሩ
CLIENT_ID='<client_id>' API_URL='<api_url>' PUBLIC_URL='<public_url>' COMMIT_SHA=$COMMIT_SHA
በዚህ ፋይል ውስጥ በአከባቢው ላይ ለሚመሰረቱ ተለዋዋጮች ቦታ ያዥዎችን መግለጽ ይፈልጋሉ። ልዩ እስከሆኑ እና በምንም መልኩ ከምንጭ ኮድዎ ጋር እስካልተደራረቡ ድረስ የፈለጋችሁት ማንኛውም ነገር ሊሆኑ ይችላሉ። ለተጨማሪ ማረጋገጫ፣ መጠቀምም ይችላሉ።
ለእነዚያ በአካባቢዎች ላይ የማይለወጡ ተለዋዋጮች (ለምሳሌ፣ የፈጸሙት ሃሽ)፣ ትክክለኛዎቹን እሴቶች በቀጥታ መጻፍ ወይም በግንባታ ስራው (እንደ $COMMIT_SHA ) ያሉ እሴቶችን መጠቀም ይችላሉ። የፊት ለፊት ማዕቀፍ በግንባታው ሂደት ውስጥ እነዚህን ቦታ ያዢዎች በትክክለኛ እሴቶች ይተካቸዋል፡
ፋይል
አሁን ከቦታ ያዥዎች ይልቅ እውነተኛ እሴቶችን ለማስቀመጥ እድሉን ያገኛሉ። ይህንን ለማድረግ ፋይል ይፍጠሩ፣ inject.py
(ፓይዘንን መርጫለሁ፣ ነገር ግን ለዚህ ዓላማ ማንኛውንም መሳሪያ መጠቀም ይችላሉ) በመጀመሪያ የቦታ ያዥዎችን ወደ ተለዋዋጭ ስሞች ካርታ መያዝ አለበት
replacement_map = { "<client_id>": "CLIENT_ID", "<api_url>": "API_URL", "<public_url>": "PUBLIC_URL", "%3Cpublic_url%3E": "PUBLIC_URL" }
public_url
ሁለት ጊዜ የተዘረዘረ መሆኑን እና ሁለተኛው ግቤት ከቅንፍ አምልጧል። በሲኤስኤስ እና በኤችቲኤምኤል ፋይሎች ውስጥ ለሚጠቀሙት ሁሉም ተለዋዋጮች ይህ ያስፈልገዎታል።
base_path = 'usr/share/nginx/html' target_files = [ f'{base_path}/static/js/main.*.js', f'{base_path}/static/js/chunk.*.js', f'{base_path}/static/css/main.*.css', f'{base_path}/static/css/chunk.*.css', f'{base_path}/index.html' ]
injector.py
ፋይልን እንፈጥራለን፣ የካርታ ስራ እና የግንባታ ቅርስ ፋይሎችን (እንደ JS፣ HTML እና CSS ፋይሎች) የምንቀበልበት እና ቦታ ያዢዎችን አሁን ካለንበት አካባቢ በተለዋዋጮች እሴቶች የምንተኩበት
import os import glob def inject_envs(filename, replacement_map): with open(filename) as r: lines = r.read() for key, value in replacement_map.items(): lines = lines.replace(key, os.environ.get(value) or '') with open(filename, "w") as w: w.write(lines) def inject(target_files, replacement_map, base_path): for target_file in target_files: for filename in glob.glob(target_file.glob): inject_envs(filename, replacement_map)
እና ከዚያ፣ በ inject.py
ፋይል ውስጥ፣ ይህን መስመር ያክሉ ( injector.py
ማስመጣትዎን አይርሱ):
injector.inject(target_files, replacement_map, base_path)
inject.py
ስክሪፕት በሚሰራበት ጊዜ ብቻ የሚሰራ መሆኑን ማረጋገጥ አለብን። Pythonን ከጫኑ እና ሁሉንም ቅርሶች ከገለበጡ በኋላ CMD
ትዕዛዝ ውስጥ ወደ Dockerfile
ማከል ይችላሉ። RUN apk add python3 COPY nginx/default.conf /etc/nginx/conf.d/default.conf COPY --from=build /app/ci /ci COPY --from=build /app/build /usr/share/nginx/html CMD ["/bin/sh", "-c", "python3 ./ci/inject.py && nginx -g 'daemon off;'"]That's it! This way, during each deployment, the pre-built files will be used, with variables specific to the deployment environment injected into them.
ያ ነው! በዚህ መንገድ፣ በእያንዳንዱ ማሰማራት ወቅት፣ ቀድሞ የተሰሩ ፋይሎች ጥቅም ላይ ይውላሉ፣ ለተሰማራ አካባቢ ልዩ ተለዋዋጮች ወደ ውስጥ ገብተዋል።
ፋይል፡-
አንድ ነገር - የእርስዎ የግንባታ ቅርሶች በፋይል ስሞቻቸው ውስጥ የይዘት hash ካካተቱ ይህ መርፌ የፋይል ስሞችን አይጎዳውም እና ይህ በአሳሽ መሸጎጫ ላይ ችግር ሊፈጥር ይችላል። ይህንን ለማስተካከል ፋይሎቹን በተከተቡ ተለዋዋጮች ካስተካከሉ በኋላ የሚከተሉትን ማድረግ አለብዎት:
ይህንን ለመተግበር የሃሽ ቤተ-መጽሐፍት አስመጪ ( import hashlib
) እና የሚከተሉትን ተግባራት ወደ inject.py
ፋይል ያክሉ።
def sha256sum(filename): h = hashlib.sha256() b = bytearray(128 * 1024) mv = memoryview(b) with open(filename, 'rb', buffering=0) as f: while n := f.readinto(mv): h.update(mv[:n]) return h.hexdigest() def replace_filename_imports(filename, new_filename, base_path): allowed_extensions = ('.html', '.js', '.css') for path, dirc, files in os.walk(base_path): for name in files: current_filename = os.path.join(path, name) if current_filename.endswith(allowed_extensions): with open(current_filename) as f: s = f.read() s = s.replace(filename, new_filename) with open(current_filename, "w") as f: f.write(s) def rename_file(fullfilename): dirname = os.path.dirname(fullfilename) filename, ext = os.path.splitext(os.path.basename(fullfilename)) digest = sha256sum(fullfilename) new_filename = f'{filename}.{digest[:8]}' new_fullfilename = f'{dirname}/{new_filename}{ext}' os.rename(fullfilename, new_fullfilename) return filename, new_filename
ሆኖም፣ ሁሉም ፋይሎች እንደገና መሰየም አያስፈልጋቸውም። ለምሳሌ፣ index.html
የፋይል ስም ሳይለወጥ መቆየት አለበት እና ይህን ለማግኘት፣ ዳግም መሰየም አስፈላጊ ከሆነ የሚጠቁም ባንዲራ የሚያከማች TargetFile
ክፍል ይፍጠሩ
class TargetFile: def __init__(self, glob, should_be_renamed = True): self.glob = glob self.should_be_renamed = should_be_renamed
አሁን በ inject.py
ውስጥ ያሉትን የፋይል ዱካዎች ድርድር በበርካታ TargetFile
ክፍል ነገሮች መተካት አለብህ
target_files = [ injector.TargetFile(f'{base_path}/static/js/main.*.js'), injector.TargetFile(f'{base_path}/static/js/chunk.*.js'), injector.TargetFile(f'{base_path}/static/css/main.*.css'), injector.TargetFile(f'{base_path}/static/css/chunk.*.css'), injector.TargetFile(f'{base_path}/index.html', False) ]
እና ባንዲራ ከተዋቀረ የፋይሉን ስም መቀየርን ለማካተት በ injector.py
ውስጥ ያለውን inject
ተግባር ያዘምኑ
def inject(target_files, replacement_map, base_path): for target_file in target_files: for filename in glob.glob(target_file.glob): inject_envs(filename, replacement_map) if target_file.should_be_renamed: filename, new_filename = rename_file(filename) replace_filename_imports(filename, new_filename, base_path)
በውጤቱም፣ አርቲፊክ ፋይሎቹ ይህንን የስያሜ ቅርጸት ይከተላሉ <origin-file-name>
። <injection-hash>
. <extension>
.
ከመርፌ በፊት የመዝገብ ስም፡-
ከክትባት በኋላ የፋይል ስም፡-
ተመሳሳይ የአካባቢ ተለዋዋጮች የተጠቃሚው አሳሽ ፋይሉን በትክክል እንዲሸጎጥ በመፍቀድ አንድ አይነት የፋይል ስም ይሰጣሉ። አሁን የእነዚህ ተለዋዋጮች ትክክለኛ ዋጋዎች በአሳሽ መሸጎጫ ውስጥ እንደሚቀመጡ ዋስትና አለ ፣ በውጤቱም - ለደንበኛው የተሻለ አፈፃፀም።
ለእያንዳንዱ አካባቢ የተለየ ግንባታዎችን የመፍጠር ባህላዊ አቀራረብ ጥቂት ወሳኝ ድክመቶችን አስከትሏል, ይህም ውስን ሀብቶች ላላቸው ቡድኖች ችግር ሊሆን ይችላል.
አሁን ረዘም ያለ የስምሪት ጊዜዎችን፣ ከመጠን በላይ ግንባታዎችን እና ለግንባር ትግበራዎች የጥራት ማረጋገጫ ስጋቶችን ሊፈታ የሚችል የመልቀቂያ ሂደት ንድፍ አለዎት - ሁሉንም። በሁሉም አከባቢዎች አዲስ የተረጋገጠ ወጥነት ደረጃ እያስተዋወቀ ነው።
N ግንባታዎችን ከመፈለግ ይልቅ አንድ ብቻ ያስፈልግዎታል። ለመጪው ልቀት፣ በቀላሉ የተሞከረውን ግንብ ማሰማራት ትችላለህ፣ ይህ ደግሞ ተመሳሳይ ግንባታ በሁሉም አካባቢዎች ጥቅም ላይ ስለሚውል የሳንካ ችግሮችን ለመፍታት ይረዳል። በተጨማሪም፣ የዚህ ስክሪፕት አፈጻጸም ፍጥነት በጣም ከተመቻቸ ግንባታ እንኳን በማይነፃፀር ፈጣን ነው። ለምሳሌ፣ በ MacBook 14 PRO፣ M1፣ 32GB ላይ ያሉ የአካባቢ መለኪያዎች የሚከተሉት ናቸው።
የእኔ አካሄድ የመልቀቂያ ሂደቱን ያቃልላል፣ ውጤታማ የመሸጎጫ ስልቶችን በመፍቀድ የመተግበሪያ አፈጻጸምን ያቆያል፣ እና ከግንባታ ጋር የተያያዙ ሳንካዎች ወደ አካባቢው ውስጥ እንደማይገቡ ያረጋግጣል። በተጨማሪም፣ ከዚህ በፊት አድካሚ በሆኑ የግንባታ ስራዎች ላይ የሚያጠፋው ጊዜ እና ጥረት ሁሉ አሁን የተሻለ የተጠቃሚ ተሞክሮ በመፍጠር ላይ ሊያተኩር ይችላል። መውደድ የሌለበት ምንድን ነው?
ከግንባታ ጋር የተያያዙ ሳንካዎች ለሌሎች አካባቢዎች ወደ መተግበሪያው እንዳይገቡ እናረጋግጣለን። በግንባታ ስርዓቶች ውስጥ ባሉ ጉድለቶች ምክንያት የሚታዩ የፋንተም ስህተቶች ሊኖሩ ይችላሉ. ዕድሉ ትንሽ ነው, ግን አሉ.