{"id":1020,"date":"2025-02-17T12:30:01","date_gmt":"2025-02-17T03:30:01","guid":{"rendered":"https:\/\/route-zero.com\/recruit\/route\/1020\/"},"modified":"2025-02-27T10:43:40","modified_gmt":"2025-02-27T01:43:40","slug":"1020","status":"publish","type":"route","link":"https:\/\/route-zero.com\/recruit\/route\/1020\/","title":{"rendered":"\u3010Docker\u3067\u7c21\u5358\u3011Python\u00d7Flask\u3067\u4f5c\u308b\u6570\u5b57\u5f53\u3066\u30b2\u30fc\u30e0Web\u30a2\u30d7\u30ea\u5165\u9580"},"content":{"rendered":"<div>\n<p>\u4eca\u56de\u306f <strong>Python\u3092\u4f7f\u3063\u305f\u6570\u5b57\u5f53\u3066\u30b2\u30fc\u30e0\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3<\/strong> \u3092\u4f5c\u6210\u3057\u3001Docker\u3067\u74b0\u5883\u3092\u69cb\u7bc9\u3059\u308b\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n<p>Python\u306e <strong>Flask<\/strong> \u3092\u4f7f\u3063\u3066Web\u30a2\u30d7\u30ea\u3092\u4f5c\u308a\u3001\u30e6\u30fc\u30b6\u30fc\u304c <strong>1\u301c100\u306e\u9593\u3067\u30e9\u30f3\u30c0\u30e0\u306b\u9078\u3070\u308c\u305f\u6570\u5b57\u3092\u5f53\u3066\u308b\u30b2\u30fc\u30e0<\/strong> \u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<br \/>\u3055\u3089\u306b\u3001Docker\u3092\u4f7f\u3063\u3066\u30a2\u30d7\u30ea\u3092\u7c21\u5358\u306b\u52d5\u4f5c\u3055\u305b\u3089\u308c\u308b\u74b0\u5883\u3092\u6574\u3048\u307e\u3059\u3002<\/p>\n<p>\u300cPython\u306eWeb\u30a2\u30d7\u30ea\u958b\u767a\u3092\u8a66\u3057\u3066\u307f\u305f\u3044\uff01\u300d\u3068\u3044\u3046\u4eba\u306b\u3074\u3063\u305f\u308a\u306e\u5185\u5bb9\u3067\u3059\u3002<br \/>\u3067\u306f\u3001\u3055\u3063\u305d\u304f\u59cb\u3081\u307e\u3057\u3087\u3046\uff01<\/p>\n<p>&#x1f449; <strong>Docker\u69cb\u7bc9\u65b9\u6cd5\u306f\u3053\u3061\u3089\u21e9<\/strong><br \/><a href=\"https:\/\/route-zero.com\/recruit\/route\/1016\/\">Docker\u306e\u69cb\u7bc9\u65b9\u6cd5<\/a><\/p>\n<hr>\n<h2>1. \u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u30d5\u30a9\u30eb\u30c0\u69cb\u6210<\/h2>\n<p>\u307e\u305a\u306f\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u30d5\u30a9\u30eb\u30c0\u69cb\u6210\u3067\u30a2\u30d7\u30ea\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/p>\n<pre><code>\u2514\u2500\u2500 <span>python-app<\/span>\r\n    \u251c\u2500\u2500 <span>flask<\/span>\r\n    \u2502   \u251c\u2500\u2500 <span>templates<\/span>\r\n    \u2502   \u2502   \u2514\u2500\u2500 <span>index<\/span><span>.html<\/span>\r\n    \u2502   \u251c\u2500\u2500 <span>app<\/span><span>.py<\/span>\r\n    \u2502   \u251c\u2500\u2500 <span>Dockerfile<\/span>\r\n    \u2502   \u2514\u2500\u2500 <span>requirements<\/span><span>.txt<\/span>\r\n    \u2514\u2500\u2500 <span>docker-compose<\/span><span>.yml<\/span><\/code><\/pre>\n<h3>\u00a0\u5404\u30d5\u30a1\u30a4\u30eb\u306e\u5f79\u5272\uff08\u308f\u304b\u308a\u3084\u3059\u3044\u4f8b\u3048\u4ed8\u304d\uff09<\/h3>\n<ul>\n<li>\n<p><strong>app.py<\/strong> : \u30b2\u30fc\u30e0\u306e\u982d\u8133 \uff08\u30b2\u30fc\u30e0\u306e\u30ed\u30b8\u30c3\u30af\u3092\u51e6\u7406\uff09<\/p>\n<\/li>\n<li>\n<p><strong>index.html<\/strong> : \u30b2\u30fc\u30e0\u306e\u898b\u305f\u76ee \uff08\u30e6\u30fc\u30b6\u30fc\u304c\u898b\u308b\u753b\u9762\uff09<\/p>\n<\/li>\n<li>\n<p><strong>Dockerfile<\/strong> : \u6599\u7406\u30ec\u30b7\u30d4 \uff08\u30a2\u30d7\u30ea\u3092\u52d5\u304b\u3059\u305f\u3081\u306e\u8a2d\u5b9a\uff09<\/p>\n<\/li>\n<li>\n<p><strong>requirements.txt<\/strong> : \u8cb7\u3044\u7269\u30ea\u30b9\u30c8\uff08\u5fc5\u8981\u306a\u30e9\u30a4\u30d6\u30e9\u30ea\u306e\u30ea\u30b9\u30c8\uff09<\/p>\n<\/li>\n<li>\n<p><strong>docker-compose.yml<\/strong> : \u30b7\u30a7\u30d5\uff08\u30b3\u30f3\u30c6\u30ca\u3092\u7ba1\u7406\u3059\u308b\u8a2d\u5b9a\uff09<\/p>\n<\/li>\n<\/ul>\n<hr>\n<h2>2. Python\u74b0\u5883\u306e\u6e96\u5099\uff08Docker\u3092\u6d3b\u7528\uff09<\/h2>\n<p>\u4eca\u56de\u306fDocker\u3092\u4f7f\u3063\u3066\u74b0\u5883\u3092\u6574\u3048\u307e\u3059\u3002<br \/>\u307e\u305a\u3001\u4ee5\u4e0b\u306e\u5185\u5bb9\u3067 <strong>docker-compose.yml<\/strong> \u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/p>\n<pre><code>version: <span>'3'<\/span>\r\n\r\nservices:\r\n  flask:\r\n    build:\r\n      context: .\/flask\r\n    ports:\r\n      - <span>\"5003:5000\"<\/span>\r\n    restart: always\r\n    volumes:\r\n      - .\/flask:<span>\/app<\/span><\/code><\/pre>\n<p>\u6b21\u306b\u3001<strong>flask \u30d5\u30a9\u30eb\u30c0<\/strong> \u306b <strong>Dockerfile<\/strong> \u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/p>\n<pre><code><span># Python\u30d9\u30fc\u30b9\u306e\u30a4\u30e1\u30fc\u30b8\u3092\u4f7f\u7528<\/span>\r\nFROM python:<span>3.9<\/span>-slim\r\n\r\n<span># \u4f5c\u696d\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u8a2d\u5b9a<\/span>\r\nWORKDIR \/app\r\n\r\n<span># \u5fc5\u8981\u306a\u30d1\u30c3\u30b1\u30fc\u30b8\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb<\/span>\r\nCOPY requirements.txt \/app\/requirements.txt\r\nRUN pip install --no-cache-dir -r requirements.txt\r\n\r\n<span># \u30b5\u30fc\u30d0\u30fc\u306e\u8d77\u52d5<\/span>\r\nCOPY . \/app\r\nCMD [<span>\"python\"<\/span>, <span>\"app.py\"<\/span>]<\/code><\/pre>\n<p><strong>requirements.txt<\/strong> \u306b\u5fc5\u8981\u306a\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u8a18\u8ff0\u3057\u307e\u3059\u3002<\/p>\n<pre><code>flask==2.1.0\r\nwerkzeug==2.0.3\r\nnumpy==1.23.5\r\nmatplotlib==3.7.1\r\nscikit-learn==1.2.1<\/code><\/pre>\n<p>Docker\u74b0\u5883\u3092\u4f5c\u6210\u3059\u308b\u306b\u306f\u3001<strong>\u30bf\u30fc\u30df\u30ca\u30eb\uff08\u30b3\u30de\u30f3\u30c9\u30d7\u30ed\u30f3\u30d7\u30c8\uff09<\/strong> \u3067\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u30eb\u30fc\u30c8\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff08python-app \u30d5\u30a9\u30eb\u30c0\uff09\u306b\u79fb\u52d5\u3057\u3001\u6b21\u306e\u30b3\u30de\u30f3\u30c9\u3092\u5b9f\u884c\u3057\u307e\u3059\u3002<\/p>\n<pre><code>docker-compose up -d --build<\/code><\/pre>\n<p>\u3053\u308c\u3067\u3001Flask\u306e\u74b0\u5883\u304c\u6574\u3044\u307e\u3057\u305f\uff01<\/p>\n<hr>\n<h2>3. Flask\u30a2\u30d7\u30ea\u306e\u4f5c\u6210<\/h2>\n<p>\u3067\u306f\u3001<strong>app.py<\/strong> \u306b\u6570\u5b57\u5f53\u3066\u30b2\u30fc\u30e0\u306e\u30ed\u30b8\u30c3\u30af\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<\/p>\n<pre><code>from flask import Flask, render_template, request\r\nimport random\r\n\r\napp = Flask(__name_<span>_<\/span>)\r\n\r\n<span># \u30b2\u30fc\u30e0\u306e\u72b6\u614b\u3092\u4fdd\u6301\u3059\u308b\u30af\u30e9\u30b9<\/span>\r\n<span><span>class<\/span> <span>GuessGame<\/span>:<\/span>\r\n    <span><span>def<\/span> __init__<span>(<span>self<\/span>)<\/span><\/span>:\r\n        <span>self<\/span>.target_number = random.randint(<span>1<\/span>, <span>100<\/span>)  <span># 1\u301c100\u306e\u30e9\u30f3\u30c0\u30e0\u306a\u6570\u5b57\u3092\u8a2d\u5b9a<\/span>\r\n        <span>self<\/span>.guesses = <span>0<\/span>  <span># \u30e6\u30fc\u30b6\u30fc\u306e\u8a66\u884c\u56de\u6570<\/span>\r\n        <span>self<\/span>.game_over = False  <span># \u30b2\u30fc\u30e0\u7d42\u4e86\u30d5\u30e9\u30b0<\/span>\r\n\r\n    <span><span>def<\/span> <span>guess<\/span><span>(<span>self<\/span>, number)<\/span><\/span>:\r\n        <span>self<\/span>.guesses += <span>1<\/span>\r\n        <span>if<\/span> number &lt; <span>self<\/span>.<span>target_number:<\/span>\r\n            <span>return<\/span> <span>\"\u5927\u304d\u3044\u6570\u5b57\u3092\u9078\u3093\u3067\u304f\u3060\u3055\u3044\u3002\"<\/span>\r\n        elif number &gt; <span>self<\/span>.<span>target_number:<\/span>\r\n            <span>return<\/span> <span>\"\u5c0f\u3055\u3044\u6570\u5b57\u3092\u9078\u3093\u3067\u304f\u3060\u3055\u3044\u3002\"<\/span>\r\n        <span>else:<\/span>\r\n            <span>self<\/span>.game_over = True  <span># \u6b63\u89e3\u306a\u3089\u30b2\u30fc\u30e0\u7d42\u4e86<\/span>\r\n            <span>return<\/span> f<span>\"\u6b63\u89e3\uff01 {self.guesses} \u56de\u3067\u5f53\u305f\u308a\u3067\u3059\uff01\"<\/span>\r\n\r\n<span># \u30b2\u30fc\u30e0\u306e\u72b6\u614b\u3092\u4fdd\u6301<\/span>\r\ngame = GuessGame()\r\n\r\n@app.route(<span>'\/'<\/span>, methods=[<span>'GET'<\/span>, <span>'POST'<\/span>])\r\n<span><span>def<\/span> <span>index<\/span><span>()<\/span><\/span>:\r\n    global game  <span># \u30b2\u30fc\u30e0\u306e\u72b6\u614b\u3092\u30b0\u30ed\u30fc\u30d0\u30eb\u306b\u5ba3\u8a00<\/span>\r\n\r\n    message = <span>\"\"<\/span>\r\n    <span>if<\/span> request.method == <span>'POST'<\/span>:\r\n        user_guess = int(request.form.get(<span>'guess'<\/span>))  <span># \u30e6\u30fc\u30b6\u30fc\u306e\u5165\u529b\u3092\u53d6\u5f97<\/span>\r\n        message = game.guess(user_guess)\r\n\r\n        <span>if<\/span> game.<span>game_over:<\/span>\r\n            game = GuessGame()  <span># \u30b2\u30fc\u30e0\u304c\u7d42\u4e86\u3057\u305f\u3089\u65b0\u3057\u3044\u30b2\u30fc\u30e0\u3092\u958b\u59cb<\/span>\r\n\r\n    <span>return<\/span> render_template(<span>'index.html'<\/span>, message=message, guesses=game.guesses, game_over=game.game_over)\r\n\r\n<span>if<\/span> __name_<span>_<\/span> == <span>'__main__'<\/span>:\r\n    app.run(debug=True, host=<span>'0.0.0.0'<\/span>, port=<span>5000<\/span>)<\/code><\/pre>\n<hr>\n<h2>4. \u30b2\u30fc\u30e0\u753b\u9762\u306e\u4f5c\u6210\uff08HTML\uff09<\/h2>\n<p>\u6b21\u306b\u3001<strong>templates\/index.html<\/strong> \u3092\u4f5c\u6210\u3057\u3001\u30e6\u30fc\u30b6\u30fc\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<\/p>\n<pre><code>&lt;!<span>DOCTYPE<\/span> html&gt;\r\n&lt;html lang=<span>\"ja\"<\/span>&gt;\r\n&lt;head&gt;\r\n    &lt;meta charset=<span>\"UTF-8\"<\/span>&gt;\r\n    &lt;meta name=<span>\"viewport\"<\/span> content=<span>\"width=device-width, initial-scale=1.0\"<\/span>&gt;\r\n    &lt;title&gt;\u6570\u5b57\u5f53\u3066\u30b2\u30fc\u30e0&lt;\/title&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n    &lt;h1&gt;\u6570\u5b57\u5f53\u3066\u30b2\u30fc\u30e0&lt;\/h1&gt;\r\n\r\n    {% <span>if<\/span> game_over %}\r\n        &lt;h2&gt;\u30b2\u30fc\u30e0\u7d42\u4e86\uff01&lt;\/h2&gt;\r\n        &lt;p&gt;{{ message }}&lt;\/p&gt;\r\n        &lt;a href=<span>\"\/\"<\/span>&gt;\u3082\u3046\u4e00\u5ea6\u30d7\u30ec\u30a4&lt;\/a&gt;\r\n    {% <span>else<\/span> %}\r\n        &lt;form method=<span>\"POST\"<\/span>&gt;\r\n            &lt;label <span>for<\/span>=<span>\"guess\"<\/span>&gt;\u4e88\u60f3\u3059\u308b\u6570\u5b57\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\uff08<span>1<\/span>\u301c<span>100<\/span>\uff09\uff1a&lt;\/label&gt;\r\n            &lt;input type=<span>\"number\"<\/span> name=<span>\"guess\"<\/span> <span>min<\/span>=<span>\"1\"<\/span> <span>max<\/span>=<span>\"100\"<\/span> <span>required<\/span>&gt;\r\n            &lt;button type=<span>\"submit\"<\/span>&gt;\u9001\u4fe1&lt;\/button&gt;\r\n        &lt;\/form&gt;\r\n        &lt;p&gt;\u3042\u306a\u305f\u306e\u4e88\u60f3\u56de\u6570\uff1a{{ guesses }} \u56de&lt;\/p&gt;\r\n        &lt;p&gt;{{ message }}&lt;\/p&gt;\r\n    {% endif %}\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/code><\/pre>\n<hr>\n<h2>5. \u30a2\u30d7\u30ea\u3092\u8d77\u52d5\u3057\u3066\u904a\u3093\u3067\u307f\u3088\u3046\uff01<\/h2>\n<p>\u3059\u3079\u3066\u306e\u8a2d\u5b9a\u304c\u5b8c\u4e86\u3057\u305f\u3089\u3001\u30a2\u30d7\u30ea\u3092\u8d77\u52d5\u3057\u3066\u307f\u307e\u3057\u3087\u3046\u3002<\/p>\n<pre><code>docker-compose up -d<\/code><\/pre>\n<p>\u3053\u308c\u3067\u3001\u30d6\u30e9\u30a6\u30b6\u3092\u958b\u3044\u3066 <strong>http:\/\/localhost:5003\u00a0<\/strong>\u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\u3068\u3001\u30b2\u30fc\u30e0\u304c\u30d7\u30ec\u30a4\u3067\u304d\u308b\u306f\u305a\u3067\u3059\uff01<\/p>\n<p><\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/route-zero.com\/recruit\/wp-content\/uploads\/2025\/02\/1020_1.png\" alt=\"\u6570\u5b57\u5f53\u3066\u30b2\u30fc\u30e0\u753b\u9762\" width=\"470\" height=\"214\" loading=\"lazy\"><\/figure>\n<p>\u88dc\u8db3: \u753b\u9762\u304c\u8868\u793a\u3055\u308c\u306a\u3044\u5834\u5408\u306f<strong>http:\/\/127.0.0.1:5003\/<\/strong>\u306b\u30a2\u30af\u30bb\u30b9\u3057\u3066\u307f\u3066\u304f\u3060\u3055\u3044\u3002\u00a0<\/p>\n<hr>\n<h2>6. \u307e\u3068\u3081<\/h2>\n<p>\u4eca\u56de\u306f <strong>Python\u306eFlask\u3092\u4f7f\u3063\u3066\u300c\u6570\u5b57\u5f53\u3066\u30b2\u30fc\u30e0\u300d\u306eWeb\u30a2\u30d7\u30ea<\/strong> \u3092\u4f5c\u6210\u3057\u3001Docker\u3067\u74b0\u5883\u69cb\u7bc9\u3059\u308b\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3057\u305f\u3002<\/p>\n<p>\u30fbFlask\u3067Web\u30a2\u30d7\u30ea\u3092\u4f5c\u308b\u65b9\u6cd5<br \/>\u30fb\u30b2\u30fc\u30e0\u306e\u30ed\u30b8\u30c3\u30af\u3092Python\u3067\u5b9f\u88c5<br \/>\u30fbHTML\u3067\u30e6\u30fc\u30b6\u30fc\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u3092\u4f5c\u6210<br \/>\u30fbDocker\u3092\u6d3b\u7528\u3057\u3066\u74b0\u5883\u69cb\u7bc9<\/p>\n<p>\u305c\u3072\u8a66\u3057\u3066\u307f\u3066\u304f\u3060\u3055\u3044\u306d\uff01<\/p>\n<\/div>\n","protected":false},"featured_media":1022,"template":"","_links":{"self":[{"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/route\/1020"}],"collection":[{"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/route"}],"about":[{"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/types\/route"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/media\/1022"}],"wp:attachment":[{"href":"https:\/\/route-zero.com\/recruit\/wp-json\/wp\/v2\/media?parent=1020"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}