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

เริ่มต้นใช้งาน

มาตั้งค่าพื้นที่เก็บข้อมูลกันเถอะ จากนั้นเราจะทดลองใช้สคริปต์ npm เพื่อให้การพัฒนาง่ายขึ้น
ในโฟลเดอร์ใหม่ ให้เรียกใช้สิ่งต่อไปนี้:

npm init -y

ธง -y ย่อมาจาก 'ใช่' หรือ 'ใช่ทั้งหมด' เมื่อคุณใช้งาน จะช่วยให้คุณสามารถเริ่มต้นไฟล์ package.json ใหม่ด้วยค่าเริ่มต้นทั้งหมดโดยไม่ต้องแจ้งให้ผู้ใช้ทราบ หมายความว่าคุณยอมรับการตั้งค่าเริ่มต้นทั้งหมดสำหรับการกำหนดค่า package.json ของคุณโดยอัตโนมัติ
ตอนนี้ มาติดตั้ง Express เป็นการขึ้นต่อกันกัน เราจะต้องมีสิ่งนี้ในไฟล์ server.js ที่เราจะสร้างล่วงหน้า

npm i express

ตอนนี้สร้างไฟล์ใหม่ —server.js ที่รูทของที่เก็บนี้ เพื่อให้ความสำคัญกับคำแนะนำแบบทีละขั้นตอนนี้เกี่ยวกับสคริปต์ npm เราจะสร้างแอปพลิเคชัน Node.js พื้นฐานโดยใช้เฟรมเวิร์ก Express เพื่อสร้างเซิร์ฟเวอร์ HTTP แบบง่ายที่ทำสิ่งต่อไปนี้:

  1. นำเข้าโมดูล Express และสร้างแอปพลิเคชัน Express
  2. ตั้งค่าพอร์ตเซิร์ฟเวอร์เป็นพอร์ต 4005 นอกจากนี้เรายังสามารถใช้ตัวแปรสภาพแวดล้อม PORT โดยใช้ process.env หรือตั้งค่าเริ่มต้นเป็น 4005
  3. กำหนดข้อความที่จะส่งเป็นการตอบสนองต่อไคลเอนต์เมื่อพวกเขาเข้าถึงเส้นทางรูท ('/')
  4. ตั้งค่าเส้นทางเพื่อจัดการคำขอ HTTP GET ไปยังเส้นทางรูท เมื่อเข้าถึงแล้วจะบันทึกข้อความไปยังคอนโซลเซิร์ฟเวอร์และส่งข้อความที่กำหนดเป็นการตอบกลับ
  5. สตาร์ทเซิร์ฟเวอร์บนพอร์ตที่ระบุ และเมื่อเซิร์ฟเวอร์เริ่มทำงาน เซิร์ฟเวอร์จะบันทึกข้อความที่กำหนดไปยังคอนโซล

server.js จะมีลักษณะดังนี้:

const express = require('express');
const app = express();
const port = process.env.PORT || 4005;
let runningMessage = 'Server is running on port ' + port;

app.get('/', (req, res) => {
    console.log('API was requested');
    res.send(runningMessage);
    }
);

const server = app.listen(port, () => {
    console.log(runningMessage);
});

ตอนนี้เรามาสร้าง Dockerfile ซึ่งตั้งค่าอิมเมจ Docker สำหรับแอปพลิเคชันของเรา โดยจะติดตั้งการขึ้นต่อกันของแอปพลิเคชัน คัดลอกโค้ดแอปพลิเคชัน และระบุคำสั่งเริ่มต้นเพื่อเริ่มแอปพลิเคชัน Node.js โดยใช้ node server.js ในขณะที่เปิดเผยพอร์ต 4005 ภายในคอนเทนเนอร์ ในการเรียกใช้แอปพลิเคชัน เราจะต้องสร้างอิมเมจจาก Dockerfile นี้ จากนั้นจึงสร้างและเริ่มต้นคอนเทนเนอร์ตามอิมเมจนั้น ในไดเร็กทอรีราก ให้สร้าง Dockerfile:

FROM node:18.10.0

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./

RUN npm install

# Bundle app source
COPY . .

# Expose port
EXPOSE 4005

# Run app
CMD [ "node", "server.js" ]

สร้าง .dockerignore ในโฟลเดอร์รูท:

node_modules
npm-debug.log

ไฟล์ .dockerignore จำเป็นสำหรับการควบคุมเนื้อหาของอิมเมจ Docker ลดขนาด เพิ่มความปลอดภัย และทำให้มั่นใจว่าข้อมูลที่ละเอียดอ่อนจะไม่ถูกเปิดเผยโดยไม่ได้ตั้งใจ
ตอนนี้ทุกอย่างได้รับการตั้งค่าแล้ว เรามาเพิ่มสคริปต์พื้นฐานสองตัวใน package.json กัน ไฟล์. ภายใต้วัตถุ scripts ให้เพิ่มสคริปต์ npm ต่อไปนี้:

"docker:build": "docker build -t npm_docker .",
"docker:run": "docker run -p 4005:4005 -d --name npm_d npm_docker",

แฟล็ก -t ในคำสั่ง docker:build ใช้เพื่อแท็กรูปภาพด้วยชื่อ (npm_docker ในกรณีนี้) ชื่อนี้จะใช้เพื่ออ้างอิงรูปภาพเมื่อเรียกใช้คอนเทนเนอร์ตามรูปภาพนั้น

ในคำสั่ง docker:run -p 4005:4005maps พอร์ต 4005 จากโฮสต์ไปยังพอร์ต 4005 ในคอนเทนเนอร์ ซึ่งช่วยให้สามารถส่งการรับส่งข้อมูลจากเครื่องโฮสต์ไปยังแอปพลิเคชันที่ทำงานภายในคอนเทนเนอร์ได้ -d บ่งชี้ว่าคอนเทนเนอร์ทำงานในโหมดเดี่ยว ซึ่งหมายความว่าคอนเทนเนอร์จะทำงานในเบื้องหลังในฐานะดีมอน แฟล็ก --name ตั้งชื่อให้กับคอนเทนเนอร์ (npm_d) ซึ่งสามารถใช้เพื่อจัดการและโต้ตอบกับคอนเทนเนอร์ในภายหลัง

แบบแผนการตั้งชื่อ

ที่นี่เราใช้รูปแบบการตั้งชื่อเช่น category:name เนื่องจากให้ความชัดเจน การจัดระเบียบ และความสอดคล้องในไฟล์ package.json

ในบริบทของ docker:build และ docker:run มันบ่งบอกถึงเจตนาและความสัมพันธ์ของสคริปต์กับการทำงานของ Docker คำนำหน้า docker: ระบุอย่างชัดเจนว่าสคริปต์เหล่านี้เกี่ยวข้องกับงาน Docker

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

หากต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับแบบแผนการตั้งชื่อ โปรดอ่านสิ่งนี้: package-json-conventions

งานพัฒนานักเทียบท่า

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

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

มาเพิ่มอีกสองสคริปต์สำหรับสิ่งนี้ เราจะตั้งชื่อมันว่า docker:stop และ docker:remove เพื่อให้สอดคล้องกับรูปแบบการตั้งชื่อของเรา
ตอนนี้ updatescripts ใน package.json ดังต่อไปนี้:

...
"scripts": {
    "docker:stop": "docker container stop npm_d",
    "docker:remove": "docker container rm npm_d",
    "docker:build": "docker build -t npm_docker .",
    "docker:run": "docker run -p 4005:4005 -d --name npm_d npm_docker",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...

ตอนนี้เมื่อคุณทำการเปลี่ยนแปลงใน server.js ของคุณ คุณสามารถสร้างคอนเทนเนอร์ที่อัปเดตใหม่ได้ แต่คุณไม่สามารถเรียกใช้ได้เนื่องจากคอนเทนเนอร์ที่มีชื่อเดียวกันกำลังทำงานอยู่แล้ว ดังนั้นคุณจำเป็นต้องรัน docker:stop และ docker:remove ก่อนที่จะรันคำสั่ง docker:run

งานพัฒนานักเทียบท่าอัตโนมัติ

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

นี่คือเมื่อมีอาร์กิวเมนต์อื่นที่มีอยู่ในเครื่องมือ Docker CLI ที่เรียกว่า "การติดตั้งระดับเสียง" มาช่วย

มาอัปเดต scripts ของเราใน package.json อย่างรวดเร็วและดูว่าการเพิ่มระดับเสียงทำอะไรได้บ้าง

...
"scripts": {
    "docker:stop": "docker container stop npm_d",
    "docker:remove": "docker container rm npm_d",
    "docker:build": "docker build -t npm_docker .",
    "docker:run": "docker run -p 4005:4005 -d --name npm_d npm_docker",
    "docker:run:dev": "docker run -p 4005:4005 -d -v %cd%:/usr/src/app --name npm_d npm_docker",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...

สคริปต์ใน docker:run:dev เกือบจะคล้ายกับสคริปต์ใน docker:run ยกเว้นอาร์กิวเมนต์ -v ตัวเลือกนี้จะเมานต์ไดเร็กทอรีการทำงานปัจจุบัน (%cd%) จากโฮสต์ไปยังไดเร็กทอรี /usr/src/app ภายในคอนเทนเนอร์

หมายเหตุ: เส้นทางทางด้านซ้ายของเครื่องหมายทวิภาค (:) คือเส้นทางไปยังตำแหน่งของซอร์สโค้ดของคุณ บนเครื่อง Windows เราสามารถใช้ %cd% และเครื่อง Linux เราสามารถใช้ $(pwd) เพื่อรับไดเร็กทอรีการทำงาน
เส้นทางไปทางด้านขวาของโคลอน (:) คือเส้นทางไดเร็กทอรีภายในคอนเทนเนอร์ Docker ตำแหน่งที่คุณต้องการเมานต์หรือแมปซอร์สโค้ดของคุณ กระบวนการนี้จะซ้อนทับซอร์สโค้ดในเครื่องของคุณจากเครื่องโฮสต์ลงในคอนเทนเนอร์ ทำให้สามารถอัปเดตแบบไดนามิกทุกครั้งที่คุณทำการเปลี่ยนแปลงโค้ดของคุณ

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

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

ตอนนี้ใน Dockerfile เราต้องทำการเปลี่ยนแปลงสองอย่าง:

  1. เพื่อให้แน่ใจว่า Nodemon พร้อมใช้งานภายในคอนเทนเนอร์ เราจึงติดตั้งมันทั่วโลก ต่างจากการพัฒนาตรงที่มักจะติดตั้ง Nodemon เป็นการพึ่งพา dev ที่นี่เราต้องการมันสำหรับระบบที่เหมือนจริงภายในคอนเทนเนอร์ เมื่อติดตั้งทั่วโลก Nodemon จะกลายเป็นเครื่องมือบรรทัดคำสั่งที่สามารถเข้าถึงได้ทั่วทั้งคอนเทนเนอร์ ด้วยวิธีนี้ เราสามารถใช้ Nodemon เพื่อเริ่มต้นและตรวจสอบแอปพลิเคชันของเราสำหรับการเปลี่ยนแปลงในสภาพแวดล้อมที่เหมือนการใช้งานจริง
  2. ในการเริ่มแอปพลิเคชันของเราโดยใช้ Nodemon ภายในคอนเทนเนอร์ เราจะแทนที่คำสั่ง node ด้วย nodemon เพื่อเรียกใช้ server.js นอกจากนี้ เราจะเพิ่มอาร์กิวเมนต์ -L เพื่อระบุโหมดนาฬิกาแบบเดิมเนื่องจากเราทำงานภายในคอนเทนเนอร์

Dockerfile ที่อัปเดตควรมีลักษณะดังนี้:

FROM node:18.10.0

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./

RUN npm install

RUN npm install -g nodemon

# Bundle app source
COPY . .

# Expose port
EXPOSE 4005

# Run app
CMD [ "nodemon", "-L", "server.js" ]

ด้วยการเปลี่ยนแปลงนี้ ตอนนี้ Dockerfile ของเราได้รับการตั้งค่าอย่างถูกต้องเพื่อใช้ Nodemon เพื่อเริ่มแอปพลิเคชันและติดตามการเปลี่ยนแปลงโค้ด

ห่อ

ก่อนที่จะรัน docker:run:dev เราจำเป็นต้องตรวจสอบให้แน่ใจว่าไม่มีคอนเทนเนอร์ใดที่ทำงานด้วยชื่อเดียวกัน เราสามารถรันสคริปต์ docker:stop และ docker:remove ที่เรากำหนดไว้ด้านบน จากนั้นจึงตามด้วย docker:build ก่อนที่จะรัน docker:run:dev

นี่คือที่ที่เราสามารถใช้ && และ &operator
ฟังก์ชั่น && เหมือนตรรกะ AND คำสั่งแรกถูกดำเนินการ และหากดำเนินการสำเร็จ (ส่งคืนโค้ดทางออกเป็น 0) คำสั่งที่สองเท่านั้นที่จะรัน ลักษณะการทำงานนี้ช่วยให้แน่ใจว่าคำสั่งที่ตามมาจะถูกดำเนินการตามเงื่อนไขตามความสำเร็จของคำสั่งก่อนหน้า ช่วยให้คุณสร้างลำดับของคำสั่งโดยที่แต่ละขั้นตอนขึ้นอยู่กับความสำเร็จของขั้นตอนก่อนหน้า
การใช้ & ในสคริปต์ npm จะเริ่มต้นการดำเนินการแบบขนาน โดยอนุญาตให้คำสั่งที่สองทำงานอย่างอิสระในเบื้องหลัง แม้ว่าคำสั่งแรก คำสั่งยังอยู่ในระหว่างดำเนินการหรือพบข้อผิดพลาด

ตอนนี้ ด้วยความรู้นี้ เรามาลองแก้ไข scripts ใน package.json :

...
"scripts": {
    "docker:stop": "docker container stop npm_d",
    "docker:remove": "docker container rm npm_d",
    "docker:build": "docker build -t npm_docker .",
    "docker:run:dev": "docker run -p 4005:4005 -d -v %cd%:/usr/src/app --name npm_d npm_docker",
    "docker:run": "npm run docker:stop & npm run docker:remove & npm run docker:build && npm run docker:run:dev"
  },
...

ที่นี่เราใช้ & ระหว่าง npm run docker:stop , npm run docker:remove และ npm run docker:build เนื่องจากแม้ในการรันใหม่ใดๆ คอนเทนเนอร์ที่มีชื่อที่กำหนด ( npm_d ในกรณีของเรา) ไม่มีอยู่ ดังนั้นสายคำสั่งจะต้องไม่หยุด และกระบวนการสร้างควรดำเนินต่อไป
อย่างไรก็ตาม && จะใช้ระหว่าง npm run docker:build ถึง npm:docker:run เนื่องจากหากกระบวนการ build ล้มเหลวไม่ว่าด้วยเหตุผลใดก็ตาม คำสั่ง run จะต้องไม่รัน และสายคำสั่งจะยุติลง

ทีนี้ลองทำให้มันง่ายขึ้นอีก เราจะใช้แพ็คเกจ npm-run-all เพื่อรันสคริปต์ npm ตามลำดับ ติดตั้ง npm-run all โดยใช้คำสั่งต่อไปนี้:

npm i npm-run-all

ตอนนี้สังเกตการเปลี่ยนแปลงใน scripts จาก package.json :

...
"scripts": {
    "docker:stop": "docker container stop npm_d || true",
    "docker:remove": "docker container rm npm_d || true",
    "docker:build": "docker build -t npm_docker .",
    "docker:run": "docker run -p 4005:4005 -d -v %cd%:/usr/src/app --name npm_d npm_docker",
    "docker:run:dev": "npm-run-all docker:*"
  },
...

สังเกตว่าเราใช้ docker:* ใน docker:run:dev อย่างไร npm-run-all มอบวิธีที่หลากหลายและมีประสิทธิภาพในการจัดการและควบคุมการทำงานของสคริปต์ npm ลดความซับซ้อนและปรับปรุงประสิทธิภาพของกระบวนการสร้างของคุณ

คำสั่งข้างต้นหมายความว่าสคริปต์ทั้งหมดที่ขึ้นต้นด้วยคำนำหน้า docker:จะทำงานตามลำดับ นี่คือจุดที่แบบแผนการตั้งชื่อของเรามีประโยชน์
ในที่นี้ || true ช่วยให้มั่นใจว่าแม้ว่า docker:stop และ docker:remove จะแสดงข้อผิดพลาด สายการบังคับบัญชาจะต้องไม่หยุด และการดำเนินการจะย้ายไปยังคำสั่ง build

และนั่นก็มาถึงแล้ว เพียงแค่เรียกใช้ docker:run:dev คุณก็พร้อมที่จะไป เมื่อใช้สคริปต์ npm คุณสามารถจัดการคอนเทนเนอร์ Docker และงานซ้ำๆ อื่นๆ ได้อย่างง่ายดาย ช่วยให้คุณมุ่งเน้นไปที่ธุรกิจหลักของคุณได้มากขึ้นและลดการตั้งค่าด้วยตนเอง

เนื้อหาเพิ่มเติมได้ที่ PlainEnglish.io.

ลงทะเบียนเพื่อรับ จดหมายข่าวรายสัปดาห์ฟรี ของเรา ติดตามเราบน Twitter, LinkedIn, YouTube และ Discord .