21 มิถุนายน 2564

Published มิถุนายน 21, 2564 by with 0 comment

รันโค้ดโปรแกรมแบบ sandbox กับ Docker ด้วย Python

สวัสดีผู้อ่านทุกท่านครับ บทความนี้ผมจะพาผู้อ่านไปเขียนโปรแกรมภาษา python เพื่อรันโค้ดโปรแกรมแบบ sandbox กับ Docker ด้วย Python แบบง่าย ๆ กันครับ

ก่อนอื่นผมขอบอกว่าบทความนี้สามารถทำงานได้เฉพาะบน Linux เท่านั้นครับ (Mac OS ไม่ได้ทดสอบ และ Windows ไม่สามารถรันได้)
Docker เป็นชุดซอฟต์แวร์สำหรับทำคอนเทนเนอร์ที่นักพัฒนาทั่วโลกรู้จักกันดี ณ เวลานี้ส่วนใหญ่คงขึ้นระบบโดยใช้ docker กันเกือบหมดแล้ว ด้วยความง่ายและรักษาความเข้ากันได้ของโปรแกรมที่เรารัน

เราสามารถใช้ docker รันโปรแกรมแบบ sandbox กันได้ ซึ่งบทความนี้ผมจะพาผู้อ่านไปเขียนโปรแกรมบนภาษา python สำหรับรันโค้ดภาษาต่าง ๆ แบบ sandbox กับ Docker บน Linux กันแบบง่าย ๆ ครับ

ก่อนอื่นให้ผู้อ่านทำการติดตั้ง docker บน Linux ให้เรียบร้อยก่อน

สามารถอ่านคู่มือการติดตั้ง Docker ได้ที่ docs.docker.com/engine/install/
หลังจากนั้น ให้ลง python3 พร้อมกับ pip3 ให้เรียบร้อย

บทความนี้เราจะใช้ไลบรารีที่ชื่อว่า epicbox

epicbox เป็นไลบรารีบนภาษา Python สำหรับรันโค้ดที่ไม่น่าเชื่อถือ มาแยกรันใน docker ซึ่งมันถูกใช้เป็นระบบตรวจคำตอบอัตโนมัติของระบบตรวจสอบคำตอบเขียนโค้ดของเว็บ Stepik.org และใช้ MIT License

เอาล่ะ ต่อไปเรามาลองรันโค้ดง่าย ๆ ใน docker แบบ sandbox กันเลย

เราจะลองโค้ดโปรแกรมภาษา python แบบ sandbox กัน โดยผมจะใช้ python 3.6

ก่อนอื่น ให้ดึง image มาเก็บไว้โดยใช้คำสั่ง 

docker pull python:3.6.5-alpine

แล้วใช้คำสั่ง

pip install epicbox

จากนั้น เรามาเขียนโปรแกรมรันโค้ด python ใน docker แบบ sandbox กัน

import epicbox

epicbox.configure(
    profiles=[
        epicbox.Profile('python', 'python:3.6.5-alpine')
    ]
)
files = [{'name': 'main.py', 'content': b'print(42)'}]
limits = {'cputime': 1, 'memory': 64}
result = epicbox.run('python', 'python3 main.py', files=files, limits=limits)
print(result)

แล้วรัน ผลลัพธ์

{'exit_code': 0, 'stdout': b'42\n', 'stderr': b'', 'duration': 0.042068, 'timeout': False, 'oom_killed': False}

จะเห็นได้ว่า ผลลัพธ์จะแสดงออกมาเป็น dict การแสดงผลผ่านหน้าจอออกมาอยู่ในคีย์ stdout รวมถึงระยะเวลาการรัน และอื่น ๆ ต่อไป เรามาลองให้รันโค้ดภาษา python โดยมี input อยู่ภายในกัน

import epicbox

epicbox.configure(
    profiles=[
        epicbox.Profile('python', 'python:3.6.5-alpine')
    ]
)
files = [{'name': 'main.py', 'content': b'print(input())'}]
limits = {'cputime': 1, 'memory': 64}
result = epicbox.run('python', 'python3 main.py', files=files, limits=limits,stdin="แมว".encode('utf-8'))
print(result)

ผลลัพธ์

{'exit_code': 0, 'stdout': b'\xe0\xb9\x81\xe0\xb8\xa1\xe0\xb8\xa7\n', 'stderr': b'', 'duration': 0.110464, 'timeout': False, 'oom_killed': False}

หรือ

{'exit_code': 0, 'stdout': b'แมว\n', 'stderr': b'', 'duration': 0.110464, 'timeout': False, 'oom_killed': False}

หากเราต้องการรันหลายไฟล์ก็แค่เพิ่มไฟล์เข้าไปใน files ได้ด้วย

import epicbox

epicbox.configure(
    profiles=[
        epicbox.Profile('python', 'python:3.6.5-alpine')
    ]
)
files = [
    {'name': 'main.py', 'content': b'import cal\nprint(cal.plue(1,2))'},
    {'name': 'cal.py', 'content': b'def plue(a,b):\n return a+b'},
]
limits = {'cputime': 1, 'memory': 64}
result = epicbox.run('python', 'python3 main.py', files=files, limits=limits)
print(result)

ผลลัพธ์

{'exit_code': 0, 'stdout': b'3\n', 'stderr': b'', 'duration': 0.036982, 'timeout': False, 'oom_killed': False}

จะเห็นได้ว่าเราสามารถเรียก import ไฟล์อื่นได้ด้วย ซึ่งเราสามารถจำกัด cpu เวลาในการรัน รวมถึงพื้นที่ memory ในการรันโค้ดได้ด้วย

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

อ่านเอกสารเพิ่มเติมได้ที่ https://github.com/StepicOrg/epicbox


0 ความคิดเห็น:

แสดงความคิดเห็น

แสดงความคิดเห็นได้ครับ :)