Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

การบรรจุแอปพลิเคชัน Rails ที่มีอยู่

ซอฟต์แวร์คอนเทนเนอร์กำลังบรรจุลงในหน่วยมาตรฐานเพื่อความสะดวกในการพัฒนาและปรับใช้ คอนเทนเนอร์รวมโค้ดจากแอปพลิเคชันของคุณเข้าด้วยกันพร้อมกับการขึ้นต่อกันทั้งหมด คอนเทนเนอร์สามารถยืนอยู่คนเดียวได้ทั้งหมด ประกอบด้วยแพ็คเกจที่มีซอฟต์แวร์ของคุณ สภาพแวดล้อมรันไทม์ และไลบรารีระบบ คอนเทนเนอร์ช่วยให้นักพัฒนาและทีมปฏิบัติการมั่นใจได้ว่าซอฟต์แวร์จะทำงานเหมือนกันโดยไม่คำนึงถึงสภาพแวดล้อม การแยกโค้ดออกจากโครงสร้างพื้นฐาน ทำให้แอปที่ "มีคอนเทนเนอร์" ทำงานแบบเดียวกันในสภาพแวดล้อมภายใน สภาพแวดล้อมการทดสอบ และการใช้งานจริง

Docker เป็นหนึ่งในแพลตฟอร์มยอดนิยมสำหรับการพัฒนาและปรับใช้ซอฟต์แวร์ ซอฟต์แวร์แพ็คเกจ Docker เป็น "อิมเมจ" ซึ่งเปลี่ยนเป็นคอนเทนเนอร์ขณะรันไทม์เมื่อดำเนินการบน Docker Image การแยกนี้ช่วยให้นักพัฒนาสามารถเรียกใช้คอนเทนเนอร์จำนวนมากบนโฮสต์เดียวได้พร้อมกัน

นักพัฒนา Rails เผชิญกับความท้าทายที่ไม่เหมือนใครเมื่อทำคอนเทนเนอร์แอปพลิเคชันที่มีอยู่ บทความนี้จะให้คำแนะนำเกี่ยวกับการบรรจุแอป Rails ที่ใช้งานได้จริง และอธิบายแนวคิดและข้อผิดพลาดที่สำคัญไปพร้อมกัน บทความนี้ไม่ใช่คำอธิบายพื้นฐานของคอนเทนเนอร์หรือนักเทียบท่า แต่เป็นการอธิบายปัญหาที่นักพัฒนาต้องเผชิญเมื่อคอนเทนเนอร์แอปพลิเคชันที่ใช้งานจริง

ข้อกำหนดเบื้องต้น

หากคุณกำลังติดตามคุณจะต้องมีแอปพลิเคชัน Rails ที่ยังไม่ได้เทียบท่า (นั่นคือคำศัพท์เฉพาะของนักเทียบท่าสำหรับ 'คอนเทนเนอร์') ฉันจะใช้ RailsWork ซึ่งเป็นโครงการด้านที่มีคุณลักษณะครบถ้วนที่ฉันเพิ่ง เปิดตัว เป็นบอร์ดงานที่เขียนด้วย Rails และปรับใช้กับ Heroku แต่ไม่ได้บรรจุในคอนเทนเนอร์

นอกจากนั้น คุณจะต้องติดตั้ง Docker ด้วย วิธีที่นิยมในการติดตั้งคือใช้ Docker Desktop ซึ่งสามารถดาวน์โหลดได้จากเว็บไซต์ทางการ

การบรรจุแอปพลิเคชัน Rails ที่มีอยู่

เมื่อดาวน์โหลดแอปแล้ว ให้เรียกใช้โปรแกรมติดตั้ง หลังจากรัน มันจะแจ้งให้คุณลากแอปพลิเคชันไปยังโฟลเดอร์แอปพลิเคชันของคุณ จากนั้น คุณจะต้องเปิดแอป จากโฟลเดอร์แอปพลิเคชันของคุณ และให้สิทธิ์พิเศษตามที่ร้องขอ เพื่อเป็นการตรวจสอบครั้งสุดท้ายเพื่อให้แน่ใจว่า Docker ได้รับการติดตั้งอย่างถูกต้อง ให้ลองแสดงรายการคอนเทนเนอร์ที่ทำงานบนเครื่องของคุณจากเทอร์มินัลของคุณโดยเรียกใช้สิ่งต่อไปนี้:

docker ps

หากมีการติดตั้ง Docker (และคุณไม่ได้ใช้งานคอนเทนเนอร์ใดๆ) คุณจะได้รับรายการว่างพร้อมส่วนหัวที่มีลักษณะดังนี้:

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

The Dockerfile

สิ่งสำคัญคือต้องเริ่มต้นด้วยคำศัพท์ที่ชัดเจนก่อนที่เราจะเจาะลึกเกินไป

หลังจากที่แอปพลิเคชัน Rails ของคุณ "เชื่อมต่อแล้ว" แอปพลิเคชันจะทำงานใน คอนเทนเนอร์ . คอนเทนเนอร์ยืนอยู่คนเดียว เปลี่ยนได้ และสร้างใหม่ได้บ่อยครั้ง

คอนเทนเนอร์สร้างขึ้นจากอิมเมจ . รูปภาพคือสแน็ปช็อตเสมือนของระบบไฟล์ที่จับคู่กับข้อมูลเมตา

Dockerfile คือซอร์สโค้ดที่อธิบายวิธีการสร้างภาพ ไฟล์ Docker มักจะรวมอยู่ในที่เก็บของแอพ Dockerized และติดตามในการควบคุมเวอร์ชันพร้อมกับแอปที่เหลือ

การสร้าง Dockerfile นั้นง่ายกว่าเสียง! Docker ให้ไวยากรณ์พิเศษแก่เราที่แยกการทำงานหนักของคอนเทนเนอร์บางอย่างออกไป ขั้นแรก ให้ไปที่ไดเร็กทอรีรากของแอปที่คุณต้องการคอนเทนเนอร์ เมื่อคุณพร้อมที่จะเริ่มทำงานแล้ว คุณควรสร้างสาขาใหม่หากคุณใช้ git คุณสามารถสร้างสาขาใหม่ได้อย่างง่ายดายด้วยชื่อ dockerize-this-app โดยเรียกใช้สิ่งต่อไปนี้:

git checkout -b dockerize-this-app

จากนั้น สร้าง Dockerfile และสั่งให้สร้างอิมเมจตามแอปพลิเคชัน Ruby ซึ่งสามารถทำได้จากบรรทัดคำสั่งโดยเรียกใช้สิ่งต่อไปนี้:

echo "FROM ruby:3.0.0" > Dockerfile

ที่นี่ เราเพิ่งสร้าง Dockerfile และเพิ่มบรรทัดที่ระบุตำแหน่งที่จะค้นหาอิมเมจคอนเทนเนอร์ Ruby โปรเจ็กต์ของฉันใช้ Ruby 3.0.0 ดังนั้นฉันจึงใช้รูปภาพที่เหมาะสม หากคุณใช้ Ruby เวอร์ชันอื่น ก็ไม่มีปัญหา Docker มีรายการรูปภาพที่รองรับทั้งหมด

ถัดไป สั่งให้ Docker สร้างอิมเมจ Docker ด้วยตนเอง:

docker build -t rails_work .

ที่นี่ คุณสามารถแทนที่ rails_work ด้วยชื่อที่คุณต้องการสำหรับภาพ และอย่าลืมใส่จุดต่อท้ายด้วย!

หากคุณต้องการดูว่ารูปภาพถูกสร้างขึ้นแล้ว คุณสามารถแสดงรายการรูปภาพในระบบของคุณได้ดังนี้:

docker image list

ภาพนี้ส่วนใหญ่ว่างเปล่าแม้ว่า; ขณะนี้ยังไม่มีแอปพลิเคชันของเรา เราสามารถสั่งให้มันเพิ่มโค้ดจากแอพของเราโดยเพิ่มสิ่งต่อไปนี้ใน Dockerfile ต่อท้าย:

ADD . /rails_work
WORKDIR /rails_work
RUN bundle install

การดำเนินการนี้จะคัดลอกไฟล์จากแอปพลิเคชันของคุณและติดตั้งการขึ้นต่อกันของแอปพลิเคชัน (ที่นี่ คุณจะแทนที่ rails_work ด้วยชื่อแอปของคุณ)

ณ จุดนี้ คุณควรรันคำสั่งอีกครั้งเพื่อสร้างภาพ:

docker image list

มีความเป็นไปได้สำหรับปัญหาที่นี่ โดยเฉพาะอย่างยิ่ง หากคุณกำลังทำสิ่งนี้กับแอปพลิเคชันที่ใช้งานจริงที่มีอยู่ Bundler อาจบ่นว่าเวอร์ชันของ Bundler ที่รูปภาพพยายามใช้นั้นแตกต่างจากที่สร้าง Gemfile.lock ไฟล์. หากเกิดเหตุการณ์นี้ คุณมีสองตัวเลือกที่ชัดเจน:

  • เปลี่ยนเวอร์ชันที่ใช้รูปภาพ
  • ลบ Gemfile.lock โดยสิ้นเชิง **หากคุณทำเช่นนี้ ตรวจสอบให้แน่ใจว่าได้ปักหมุดเวอร์ชันของอัญมณีที่คุณต้องการในเวอร์ชันเฉพาะ เนื่องจากไฟล์ล็อคจะถูกสร้างขึ้นใหม่ทั้งหมด

หากการติดตั้งบันเดิลของคุณยังคงล้มเหลว คุณอาจต้องติดตั้งเพิ่มเติมใน Dockerfile :

RUN apt-get update && apt-get install -y shared-mime-info

หากคุณยังคงประสบปัญหา คุณอาจเลือกรูปภาพ Ruby ที่ไม่ถูกต้องเพื่อใช้เป็นพื้นฐาน ดังนั้นจึงควรเริ่มการสอบสวนที่นั่น

นี่เป็นโอกาสที่ดีในการตั้งค่าตัวแปรสภาพแวดล้อม :

ENV RAILS_ENV production
ENV RAILS_SERVE_STATIC_FILES true

ถัดไป เพิ่มบรรทัดเพื่อแสดงพอร์ต 3000 ซึ่งเป็นที่ที่ Rails ทำงานโดยค่าเริ่มต้น:

EXPOSE 3000

สุดท้าย สั่งให้คอนเทนเนอร์เปิด bash shell เมื่อเริ่มทำงาน:

CMD ["bash"]

โดยรวมแล้ว Dockerfile ของคุณควรมีลักษณะดังนี้ (โดยแทนที่ชื่อ rails_work):

FROM ruby:3.0.0

ADD . /rails_work
WORKDIR /rails_work
RUN bundle install

ENV RAILS_ENV production
ENV RAILS_SERVE_STATIC_FILES true

EXPOSE 3000
CMD ["bash"]

คำอธิบายคำสั่งนักเทียบท่า

จะช่วยให้เข้าใจคำสั่ง Dockerfile ที่พบบ่อยที่สุดบางส่วนได้อย่างแน่นอน

  • FROM -> เป็นตัวกำหนดว่าภาพใดที่จะใช้เป็นฐาน
  • RUN -> ดำเนินการคำสั่ง ภายใน ภาชนะ
  • ENV -> สิ่งนี้กำหนดตัวแปรสภาพแวดล้อม
  • WORKDIR -> สิ่งนี้จะเปลี่ยนไดเร็กทอรีที่คอนเทนเนอร์ใช้อยู่
  • CMD -> ระบุโปรแกรมที่จะรันเมื่อคอนเทนเนอร์เริ่มทำงาน

นักเทียบท่าเขียน

ตามเอกสารของ Docker "เขียน" เป็นเครื่องมือสำหรับสร้าง (และเริ่มต้น) แอปพลิเคชันที่มีคอนเทนเนอร์ Docker หลายตัว ทุกสิ่งที่จำเป็นในการรวมคอนเทนเนอร์ที่จำเป็นของแอปพลิเคชันจะได้รับการสรุปไว้ใน YAML เมื่อมีคนเรียกใช้ docker-compose up , คอนเทนเนอร์ถูกสร้างขึ้น! Docker-compose ช่วยให้เราอธิบายการกำหนดค่าคอนเทนเนอร์ของเราได้อย่างชัดเจน

ก่อนสร้างไฟล์ Docker Compose คุณต้องระบุให้ Docker ทราบว่าไฟล์ใดควรแยกออกจากรูปภาพที่สร้างขึ้น สร้างไฟล์ชื่อ .dockerignore . (สังเกตจุด!) ในไฟล์นี้ ให้วางสิ่งต่อไปนี้:

.git
.dockerignore
.env

หาก Gemfile ของคุณได้รับการดูแลโดยกระบวนการสร้าง อย่าลืมเพิ่ม Gemfile.lock เพื่อละเว้นข้างต้น

จากนั้น สร้างไฟล์ชื่อ docker-compose.yml . นี่คือที่ที่เราจะอธิบายการกำหนดค่าคอนเทนเนอร์ของเรา เราจะเริ่มด้วยสิ่งนี้สำหรับเนื้อหาของไฟล์:

version: '3.8'
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/Rails-Docker
    ports:
      - "3000:3000"
    depends_on:
      - db
volumes:
  postgres:

ไฟล์นี้สร้างสองบริการ:บริการหนึ่งเรียกว่า db และอีกอันเรียกว่า web . คอนเทนเนอร์ db จะถูกสร้างขึ้นจากอิมเมจที่สร้างไว้ล่วงหน้าสำหรับ postgres และคุณควรแทนที่ค่าที่เกี่ยวข้องสำหรับ POSTGRES_USER และ POSTGRES_PASSWORD . คุณควร ระวังอย่าใส่ความลับในการผลิต ในไฟล์นี้ - ดูข้อมูลเพิ่มเติมในส่วน "การจัดการความลับ" ด้านล่าง

เว็บคอนเทนเนอร์สร้างขึ้นจาก Dockerfile ของเรา จากนั้นจึงเริ่มเซิร์ฟเวอร์ Rails บนพอร์ต 3000 ที่ที่อยู่ IP 0.0.0.0 จากนั้นพอร์ตภายใน 3000 จะจับคู่กับพอร์ต 3000 จริง

และสุดท้าย เรามีโวลุ่ม Postgres เพื่อยืนยันข้อมูลของเรา

การจัดการความลับ

การตรวจสอบสิทธิ์ ณ เวลาสร้างอาจเป็นปัญหาสำหรับแอปพลิเคชันที่ใช้งานจริง บางทีแอปพลิเคชันของคุณอาจค้นหา Gems จากที่เก็บส่วนตัว หรือคุณเพียงแค่ต้องจัดเก็บข้อมูลรับรองฐานข้อมูล

ข้อมูลใดๆ ที่อยู่ใน Dockerfile โดยตรงจะถูกอบลงในอิมเมจคอนเทนเนอร์ตลอดไป และนี่คือหลุมพรางด้านความปลอดภัยทั่วไป

หากคุณใช้ตัวจัดการข้อมูลประจำตัวของ Rails การให้สิทธิ์เข้าถึง Docker (หรือโฮสต์สำหรับเรื่องนั้น) นั้นค่อนข้างไม่สำคัญ ในไฟล์ Docker Compose คุณเพียงแค่ระบุ RAILS_MASTER_KEY ตัวแปรสภาพแวดล้อม สำหรับเป้าหมายการเขียนที่กำหนด คุณระบุคีย์ภายใต้ environment ส่วนหัวซึ่งคุณต้องสร้างหากยังไม่ได้สร้าง ไฟล์นักเทียบท่าจากด้านบนจะกลายเป็นดังต่อไปนี้:

version: '3.8'
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/Rails-Docker
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      - RAILS_MASTER_KEY=this_would_be_the_key
volumes:
  postgres:

ตอนนี้มันทิ้งคุณไว้ที่ทางแยก คุณอาจต้องการให้ไฟล์นี้ผูกมัดกับการควบคุมต้นทาง แต่คุณ ไม่ต้องการให้มาสเตอร์คีย์ของคุณหรือแม้แต่รหัสผ่านฐานข้อมูลของคุณถูกติดตามโดยตัวควบคุมต้นทางอย่างแน่นอน เนื่องจากนี่อาจเป็นปัญหาด้านความปลอดภัยที่เป็นอันตรายอีกประการหนึ่ง ทางออกที่ดีที่สุดคือการใช้ dotenv gem เพื่อให้คุณสามารถเข้าถึงข้อมูลประจำตัวเหล่านี้โดยพร็อกซี เก็บไว้ใน ไฟล์อื่น ที่ไม่ได้ติดตามโดยการควบคุมแหล่งที่มา

การเรียกใช้แอปพลิเคชัน Dockerized

สุดท้าย คุณสามารถเรียกใช้แอปพลิเคชันเทียบท่าด้วยคำสั่งต่อไปนี้:

docker compose up

เชื่อหรือไม่ แค่นั้นแหละ! Docker-compose ทำให้การหมุนคอนเทนเนอร์เป็นเรื่องง่าย โดยเฉพาะอย่างยิ่งเมื่อพูดถึงอาร์กิวเมนต์บรรทัดคำสั่ง

หากคุณต้องการรายการคอนเทนเนอร์ที่ทำงานอยู่ ให้เรียกใช้สิ่งต่อไปนี้:

docker ps

หากชื่อคอนเทนเนอร์ Rails ของคุณคือ web คุณสามารถรันคำสั่งได้ด้วยวิธีที่ค่อนข้างตรงไปตรงมา ตัวอย่างเช่น หากคุณต้องการเรียกใช้คอนโซล Rails สิ่งที่คุณต้องทำคือเรียกใช้สิ่งต่อไปนี้:

docker exec -it web rails console

หากคุณต้องการแค่ bash shell ภายในคอนเทนเนอร์ ให้เรียกใช้สิ่งต่อไปนี้แทน:

docker exec -it web bash

ข้อผิดพลาดบางอย่างเช่นที่ระบุไว้ที่นี่

ปัญหาทั่วไปอย่างหนึ่งของแอปพลิเคชัน Rails ที่เทียบชิดขอบในการผลิตคือการจัดการกับบันทึก ไม่ควรอยู่ในระบบคอนเทนเนอร์ในระยะยาว นักเทียบท่าแนะนำว่าบันทึกเพียงเปลี่ยนเส้นทางไปยัง STDOUT สามารถกำหนดค่าได้อย่างชัดเจนใน config/application.rb .

ปัญหาทั่วไปอีกประการหนึ่งคือเรื่องจดหมาย หากแอปพลิเคชันของคุณใช้จดหมาย คุณต้องกำหนดการตั้งค่าการเชื่อมต่ออย่างชัดเจน . SMTP เป็นวิธีการจัดส่งที่สมบูรณ์แบบและมักจะทำงานได้ดีกับค่าเริ่มต้น แต่เราต้องระวังในการตั้งค่าตำแหน่งเซิร์ฟเวอร์และการตั้งค่าอื่นๆ เพื่อให้ตรงกับการกำหนดค่าคอนเทนเนอร์ของเรา

หากคุณมีผู้ปฏิบัติงานหรืองานเบื้องหลัง เช่น sidekiq จากนั้นคุณต้องเรียกใช้ในคอนเทนเนอร์ของตัวเอง

บทสรุป

การบรรจุแอปพลิเคชัน Rails เวอร์ชันใช้งานจริงมาพร้อมกับความท้าทายต่างๆ อย่างที่คุณเคยเห็นมาอย่างไม่ต้องสงสัย เมื่อแอปพลิเคชันของคุณเติบโตขึ้น มีแนวโน้มว่าจะได้สะสมการพึ่งพาจำนวนมากซึ่งทำให้การย้ายข้อมูลเช่นนี้มีความท้าทาย ไม่ว่าจะเป็นพนักงานที่ทำงานเบื้องหลัง จดหมาย หรือความลับ มีรูปแบบที่กำหนดไว้เพื่อจัดการกับข้อผิดพลาดส่วนใหญ่ เมื่องานเริ่มต้นในการรับแอปพลิเคชันที่ใช้งานจริงที่ทำงานกับ Docker เสร็จสมบูรณ์ ความง่ายในการเปลี่ยนแปลงและการปรับใช้ในอนาคตจะทำให้การลงทุนคุ้มค่า