VSCode DevContainer: เครื่องมือพัฒนาสารพัดใช้
DevContainer คืออะไร?
ผู้อ่านเคยประสบกับปัญหาการพัฒนาโปรแกรมแบบนี้บ้างหรือเปล่า? ทำไมกว่าจะ Build ได้มันยากจังง? ทำไมต้อง Install อะไรหลายอย่าง? Project นี้ Framework ใช้ Version อะไรนะ? เครื่องเพื่อน Build ผ่านทำไมเครื่องฉัน Build พัง? หากปัญหาที่กล่าวมาฟังดูคู้นนน คุ้น ผู้เขียนคิดว่า DevContainer จะเป็นตัวเลือกหนึ่งที่สามารถใช้แก้ปัญหาดังกล่าวได้
สำหรับบทความนี้ผู้เขียนขออนุมานก่อนว่าผู้อ่านคุ้นชินกับ Docker อยู่แล้วประมาณหนึ่ง (แต่ถ้ายังไม่เคยลอง ท่านผู้อ่านสามารถเริ่มทำความรู้จักกับ Docker ก่อนได้ที่นี่) สมมุติว่าเรามี Docker Container ซึ่งเราสามารถติดตั้งอะไรก็ได้ลงไปบน Container ตัวนี้ ทีนี้จะเกิดอะไรขึ้นถ้าเราติดตั้งชุดพัฒนาทุกอย่างที่เราต้องการบน Container ตัวนั้น? คำตอบคือเราจะสามารถ Build/Compile และ Run สิ่งที่เราเขียนได้นั่นเอง ทีนี้ลองคิดต่อจะเกิดอะไรขึ้นอีกถ้า VSCode มันสามารถต่อเข้าไปยัง Container ตัวนี้และใช้ Container ตัวนี้เป็น Workspace? นั่นคือเราใช้ VSCode เป็นตัวเขียน Code ซึ่งทำงานหลังบ้านใน (Dev)Container นั่นเอง…
ขออนุญาตอ้างอิง(ไม่ได้ขโมยนะครับ) เอารูปจากเวป VSCode มาใช้ประกอบการอธิบายนะครับ

จากรูปจะเห็นได้ว่ากรอบด้านซ้ายมือ Local OS เป็นตัวแทนของ OS บนเครื่องจริง ๆ ของท่านผู้อ่าน (โดยทั่วไปคงจะเป็น Windows) และซ้ายมือ Container นั่นคือ Docker Container ที่ VSCode จะใช้เป็น Workspace ในการพัฒนา ดังนั้นไม่ว่าผู้อ่านจะพัฒนาภาษาอะไร (หมายถึงภาษาคอมพิวเตอร์นะครับ ^_^’’’) ก็จะใช้เครื่องมือบนเครื่องอยู่เพียงสามสี่อย่างเท่านั้น นั่นก็คือ…
เครื่องมือที่ต้องใช้
- Source Control (เช่น Git)
- Docker Desktop
- Visual Studio Code (VSCode)
- Remote – Containers (VSCode Plugin Extension)
เพียงแค่ผู้อ่านติดตั้งเครื่องมือเหล่านี้ ก็สามารถลงมือพัฒนาได้เลย (สะดวกสบายมั้ย!)
การทดลองใช้
หากผู้อ่านไม่มี Source Code หรือ Project อยู่ในมือเลย ก็สามารถเริ่มสร้างใหม่ได้จากศูนย์ โดยการใช้ VSCode ช่วย ให้ผู้อ่านทำตามขั้นตอนดังนี้
- สร้าง Folder ขึ้นมาบนเครื่องผู้อ่านที่ใดสักแห่ง (ในที่นี้ผู้เขียนทำบน Desktop เพื่อความง่าย)
- สั่งให้ VSCode เปิด Folder นั้นขึ้นมาด้วย Menu Open with Code
- คลิกปุ่ม Open a Remote Window ที่มุมล่างซ้ายของ VSCode
- เลือกเมนู Reopen in Container
- จากนั้นเลือกภาษาหรือ Stack ที่ผู้อ่านต้องการทดลองเล่นด้วย (ในที่นี้ผู้เขียนเลือก Node.js & Mongo DB แต่ผู้อ่านอาจจะลองเลือกไม่เหมือนผู้เขียนก็ได้)
- หลักจากนั้น VSCode ไฟล์ที่เกี่ยวกับ DevContainer (Folder .devcontainer) ให้
และถ้าหากเราคลิก Starting Dev Container (Show Log) เราจะเห็น Log Message ใน Terminal - นอกจากนั้น VSCode ยัง Docker Container มาให้พร้อม ๆ กันด้วยเลยย
- จากนี้ถ้าเราเพิ่ม Terminal เข้ามาใหม่
เราจะพบว่า Shell นั้นจะอยู่ใน Docker Container เสมือนกับเราใช้คำสั่ง docker exec เลย - เราสามารถใช้คำสั่งสร้าง Project จากใน Shell ได้เลย (เช่น npm init)
การแก้ไขไฟล์ภายใต้โฟลเดอร์ .devcontainer ที่มีอยู่
ภายใต้ Folder .devcontainer นั้นจะมีไฟล์หลักอยู่สามไฟล์ ได้แก่
- devcontainer.json
- docker-compose.yml
- Dockerfile
devcontainer.json
เป็นไฟล์หลักที่บ่งบอก VSCode ว่า Parent Folder นี้มี DevContainer อยู่ด้วย ภายในไฟล์นี้มีหน้าตาตั้งต้นดังนี้
{
"name": "Node.js & Mongo DB",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"mongodb.mongodb-vscode"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [3000, 27017],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node"
}
คำอธิบาย Property
- name คือชื่อที่ปรากฎอยู่ในปุ่ม Open a Remote Window ที่มุมล่างซ้ายของ VSCode หลังจากที่ DevContainer สร้างสำเร็จ dockerComposeFile ตรงนี้เราสามารถเลือกได้ระหว่าง dockerComposeFile และ build – dockerComposeFile จะระบุไฟล์ docker-compose ประเภท YAML ซึ่งใช้เมื่อเราอยากสร้าง Container หลายอัน (เช่น App หนึ่งอัน Database อีกอัน เป็นต้น) เราจะต้องใส่ Property service และ workspace ด้วย เพื่อบอก VSCode ว่าเราจะใช้ Service ใดและ Directory ไหนคือ Workspace (ให้ VSCode เปิด Container ตัวไหนขึ้นมา และเปิด Folder ไหน) – build ถ้าเราเลือกเปลี่ยน dockerComposeFile เป็น build จะชี้ว่าเราสร้าง Container ขึ้นมาจาก dockerFile โดยตรง ตัวอย่างเช่น
{
...
"build": {
"dockerfile": "Dockerfile",
"args": {
"DOCKER_ARGUMENT_1": "TEST_VALUE",
}
},
}
- extensions เราสามารถใส่รายการ Extension ของ VSCode ที่ต้องการใช้พัฒนาโดยเฉพาะกับ Framework ที่เราต้องการ โดย Extension ที่ใส่ไว้ใน Property นี้จะติดตั้งใน Container เท่านั้น (ไม่กระทบกับเครื่องจริงของผู้อ่าน) ดังนั้นจึงเป็นการช่วยลดจำนวน Extension ให้เหลือเฉพาะที่เราต้องการใช้จริงกับโปรเจกต์ ณ ขณะที่เรากำลังพัฒนา
- postCreateCommand เป็นคำสั่งที่จะให้ Container Run เสร็จหลังจากการสร้าง Container เสร็จแล้ว (เช่น yarn install) ตรงนี้ในปัจจุบัน (VSCode 1.57) ยังไม่รองรับคำสั่งหลายคำสั่ง ดังนั้นถ้าต้องการทำหลายคำสั่ง เราจะสร้างไฟล์คำสั่งนามสกุล .sh แล้วนำมาสั่ง Execute ตรงนี้ได้
- remoteUser มีไว้ระบุชื่อ User ที่ต้องการ login เข้าใช้ Container (มองง่าย ๆ ว่าจะใช้เป็น Linux Username ใดในการ login เข้า Container)
docker-compose.yml
เหมือนกับไฟล์ docker-compose.yml ธรรมดา ที่ใช้กับคำสั่ง docker compose โครงสร้างภายในคือ Docker Compose YAML เราสามารถทำทุกอย่างได้เหมือนกับ Docker Compose ปกติ (ตัวอย่างเช่น เพิ่ม Service ใส่ Volume หรือใส่ Environment Variable เป็นต้น)
Dockerfile
เหมือนกับไฟล์ DockerFile ธรรมดา ที่ใช้กับคำสั่ง docker build โครงสร้างภายในคือ Docker File เราสามารถทำได้เหมือนกับ Docker File ปกติเช่นกัน
ทดลองสร้าง API Server
ในห้วข้อนี้ผู้เขียนจะพาผู้อ่านทดลองการสร้าง API Server ขึ้นมาใน DevContainer ที่เราได้สร้างกันไว้ในหัวข้อ การทดลองใช้ ให้ผู้อ่านทำตามขั้นตอนนี้ได้เลยยย
- ใน VSCode เปิด Terminal ขึ้นมา (Terminal > New Terminal หรือ Ctrl + `) แล้วสั่ง install Express.js โดย Express.js เป็น Library ที่ทำให้ Node Project ที่เราสร้างขึ้นหน้าที่เป็น API Server ได้
$ yarn add express

- สร้างไฟล์ index.js

- เปิดไฟล์ index.js แล้วใส่ Code เพื่อทำ API Server ดังนี้
const express = require('express');
const app = express();
const port = 3000;
app.get('/hello-world', (req, res) => {
res.send({ "message": 'สวัสดีชาวโลก!' });
});
app.listen(port, () => {
console.log(`API Server Start http://localhost:${port}`);
});
- ใส่คำสั่ง Run ใน VSCode Terminal ดังนี้
$ node index.js
หาก Run สำเร็จ Terminal จะแสดงผลลัพธ์ดังนี้

- เปิด Browser (ค่ายไหนก็ได้) ขึ้นมา แล้วกรอก URL localhost:3000/hello-world จะเห็นผลลัพธ์การตอบกลับจาก API Server ดังนี้

การแก้ไขปัญหาเบื้องต้น
ถ้าหาก VSCode ไม่สามารถสร้าง Docker Container ได้สำเร็จจะเกิด Message Box ขึ้นมาดังนี้

ผู้อ่านสามารถลองคลิกปุ่ม Retry หรือ Open docker-compose.yml Locally ก็ได้ ถ้าหาก Retry แล้วไม่สำเร็จให้ลองกดปุ่ม Open docker-compose.yml Locally แล้ว VSCode จะแสดงหน้าต่าง Log ขึ้นมา

จากนั้นให้พิจารณา Log ที่เกิดขึ้น (ในที่นี้ผู้เขียนใส่ย่อหน้าใน docker-compose.yml ผิด)


แล้วแก้ไขให้ถูกต้องแล้วลองคลิกเลือกเมนู Reopen in Container

จะเอาไปใช้จริง ๆ ยังไงดี?
อย่างที่ผู้เขียนเล่าไปแล้วว่า DevContainer นั้นใช้ docker-compose เป็นแกน ดังนั้นผู้อ่านอาจจะลองหา Framework ในเมนูดูก่อน เผื่อว่าอาจจะมีสิ่งที่ผู้อ่านต้องการจะสร้างอยู่ในนั้นแล้ว ถ้าเป็นแบบนี้ผู้อ่านไม่ต้องทำอะไรมาก แต่ถ้าหากผู้อ่านต้องการปรับเปลี่ยน Compose (ยกตัวอย่างเช่น เปลี่ยนจาก MongoDB เป็น MySQL เป็นต้น) อันนี้ก็สามารถเปลี่ยน docker-compose.yml ได้เลย
ข้อสังเกตอีกประการหนึ่งก็คือ เมื่อเราใช้ DevContainer เราจะไม่ติดตั้งเครื่องมือที่เกี่ยวกับภาษา หรือ Framework ที่เราจะพัฒนา (เช่นถ้าผู้อ่านจะพัฒนา Node ผู้อ่านก็ไม่ต้องติดตั้ง Node บนเครื่อง) เพราะเครื่องมือต่าง ๆ นั้นอยู่ภายใน Container อยู่แล้ว
สรุป DevContainer เป็นเครื่องมืออีกชิ้นหนึ่งที่ทำให้เครื่องผู้อ่าน ไม่รก และไม่ติดปัญหาตอน Build/Run สามารถจำลอง Database โดยไม่ต้องกังวลเรื่องข้อมูล (เพราะเริ่มต้นจาก Database เปล่า ๆ ได้) ทำให้ชีวิตง่ายขึ้น ลองเล่นกับมันดูนะครับ
เนื้อหาโดย ประณิธาน ธรรมเจริญพร
ตรวจทานและปรับปรุงโดย พีรดล สามะศิริ