├── .devcontainer
├── cpu-uv
│ ├── Dockerfile
│ └── devcontainer.json
├── gpu-sagemaker
│ ├── Dockerfile
│ ├── devcontainer.json
│ ├── init.sh
│ └── requirements.txt
└── gpu-uv
│ ├── Dockerfile
│ └── devcontainer.json
├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE
├── README.md
├── docs
├── coding-guidelines.md
└── operation_ec2.md
├── img
├── cf-ec2-architecture.png
└── vscode-ssm-ec2.png
├── ops_ec2
└── lambda_function.py
├── pyproject.toml
├── setup
├── cf-template
│ └── cf-ec2.yaml
├── check_vm_env
│ ├── check_cuda_torch.sh
│ └── mnist_example
│ │ ├── LICENSE
│ │ └── mnist.py
├── coding_agent
│ ├── claude-code
│ │ ├── README.md
│ │ └── setup_claude_code.sh
│ └── cline
│ │ ├── .clineignore
│ │ ├── .clinerules
│ │ └── README.md
├── make_new_project.sh
├── ssh
│ ├── ssh_setup_linux.sh
│ └── ssh_setup_win.bat
└── vscode
│ ├── vscode_local_setup_linux.sh
│ ├── vscode_local_setup_win.bat
│ ├── vscode_settings.json
│ └── vscode_vm_setup.sh
├── src
├── __init__.py
└── main.py
└── uv.lock
/.devcontainer/cpu-uv/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ghcr.io/astral-sh/uv:debian
2 |
3 | # Install awscli v2
4 | RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
5 | && unzip awscliv2.zip \
6 | && ./aws/install \
7 | && rm -r aws \
8 | && rm awscliv2.zip
9 |
10 | # Add non-root user
11 | ARG USERNAME=vscode
12 | ARG USER_UID=1000
13 | ARG USER_GID=$USER_UID
14 |
15 | # Install sudo and add non-root user
16 | RUN apt-get update \
17 | && groupadd --gid $USER_GID $USERNAME \
18 | && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
19 | && apt-get install -y sudo \
20 | && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
21 | && chmod 0440 /etc/sudoers.d/$USERNAME
22 |
23 | # Switch to non-root user
24 | USER $USERNAME
25 |
26 | # Set working directory
27 | WORKDIR /home/$USERNAME/
28 |
29 | # add ll alias
30 | RUN echo 'alias ll="ls -la"' >> ~/.bash_aliases
31 |
--------------------------------------------------------------------------------
/.devcontainer/cpu-uv/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cpu-uv", // [Optional] Your project name here
3 | "build": {
4 | "dockerfile": "Dockerfile"
5 | },
6 | "workspaceFolder": "/workspace",
7 | "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
8 | "mounts": [
9 | "source=uv-cache,target=/root/.cache/uv,type=volume", // uv cache
10 | "source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached" // git config
11 | ],
12 | "remoteEnv": {
13 | "UV_COMPILE_BYTECODE": "1",
14 | "UV_LINK_MODE": "copy"
15 | },
16 | "postCreateCommand": "uv sync --frozen && . .venv/bin/activate && uv add pre-commit && uv run pre-commit install",
17 | // Configure tool-specific properties.
18 | "customizations": {
19 | // Configure properties specific to VS Code.
20 | "vscode": {
21 | "settings": {
22 | "terminal.integrated.profiles.linux": {
23 | "bash": {
24 | "path": "/bin/bash"
25 | }
26 | },
27 | // notebook
28 | "notebook.formatOnSave.enabled": true,
29 | "notebook.codeActionsOnSave": {
30 | "notebook.source.fixAll": "explicit",
31 | "notebook.source.organizeImports": "explicit"
32 | },
33 | // python
34 | "[python]": {
35 | "editor.formatOnSave": true,
36 | "editor.defaultFormatter": "charliermarsh.ruff",
37 | "editor.codeActionsOnSave": {
38 | "source.fixAll": "explicit", // fix lint violations on-save
39 | "source.organizeImports": "explicit" // organize imports on-save
40 | }
41 | },
42 | "mypy-type-checker.args": [
43 | "--config=${workspaceFolder}/pyproject.toml"
44 | ],
45 | "python.defaultInterpreterPath": "./.venv/bin/python",
46 | "python.analysis.typeCheckingMode": "basic",
47 | "python.analysis.inlayHints.functionReturnTypes": true,
48 | "python.analysis.inlayHints.variableTypes": true,
49 | "python.analysis.completeFunctionParens": true,
50 | // visibility
51 | "editor.bracketPairColorization.enabled": true,
52 | "editor.guides.bracketPairs": "active",
53 | // markdown
54 | "[markdown]": {
55 | "editor.wordWrap": "bounded",
56 | "editor.defaultFormatter": "esbenp.prettier-vscode"
57 | }
58 | },
59 | "extensions": [
60 | // python
61 | "ms-python.python",
62 | "ms-python.vscode-pylance",
63 | "ms-python.mypy-type-checker",
64 | "charliermarsh.ruff",
65 | "donjayamanne.python-extension-pack",
66 | // jupyter
67 | "ms-toolsai.jupyter",
68 | "ms-toolsai.jupyter-keymap",
69 | "ms-toolsai.jupyter-renderers",
70 | // git
71 | "mhutchie.git-graph",
72 | "eamodio.gitlens",
73 | "donjayamanne.git-extension-pack",
74 | // markdown
75 | "yzhang.markdown-all-in-one",
76 | "shd101wyy.markdown-preview-enhanced",
77 | "esbenp.prettier-vscode",
78 | // shell
79 | "mads-hartmann.bash-ide-vscode",
80 | "timonwong.shellcheck",
81 | "foxundermoon.shell-format",
82 | // visibility
83 | "mechatroner.rainbow-csv",
84 | "GrapeCity.gc-excelviewer",
85 | "janisdd.vscode-edit-csv",
86 | "monokai.theme-monokai-pro-vscode",
87 | "vscode-icons-team.vscode-icons",
88 | "MS-CEINTL.vscode-language-pack-ja",
89 | // other
90 | "github.copilot",
91 | "github.copilot-chat",
92 | "amazonwebservices.aws-toolkit-vscode",
93 | "amazonwebservices.amazon-q-vscode",
94 | "saoudrizwan.claude-dev"
95 | ]
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/.devcontainer/gpu-sagemaker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM 763104351884.dkr.ecr.ap-northeast-1.amazonaws.com/pytorch-training:2.6.0-gpu-py312-cu126-ubuntu22.04-sagemaker
2 | # FROM 763104351884.dkr.ecr.ap-northeast-1.amazonaws.com/pytorch-training:2.6.0-cpu-py312-ubuntu22.04-sagemaker
3 | # see: https://github.com/aws/deep-learning-containers/blob/master/available_images.md
4 |
5 | COPY ./requirements.txt /tmp/
6 |
7 | # Install libraries
8 | RUN pip3 install --no-cache-dir -r /tmp/requirements.txt
9 |
10 | # Uninstall awscli v1 and install awscli v2
11 | RUN pip uninstall awscli -y \
12 | && curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
13 | && unzip awscliv2.zip \
14 | && ./aws/install \
15 | && rm -r aws \
16 | && rm awscliv2.zip
17 |
--------------------------------------------------------------------------------
/.devcontainer/gpu-sagemaker/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gpu-sagemaker", // [Optional] Your project name here
3 | "build": {
4 | "dockerfile": "Dockerfile"
5 | },
6 | "workspaceFolder": "/workspace",
7 | "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
8 | "initializeCommand": "bash ${localWorkspaceFolder}/.devcontainer/gpu-sagemaker/init.sh",
9 | "runArgs": [
10 | "--gpus",
11 | "all",
12 | "--shm-size",
13 | "32g" // shared memory size
14 | ],
15 | "features": {
16 | "ghcr.io/devcontainers/features/common-utils:2": {
17 | "installZsh": false,
18 | "installOhMyZsh": false,
19 | "installOhMyZshConfig": false,
20 | "upgradePackages": false,
21 | "username": "vscode", // Add non-root user
22 | "userUid": "automatic",
23 | "userGid": "automatic"
24 | }
25 | },
26 | "remoteUser": "vscode", // use non-root user
27 | // Configure tool-specific properties.
28 | "customizations": {
29 | // Configure properties specific to VS Code.
30 | "vscode": {
31 | "settings": {
32 | "terminal.integrated.profiles.linux": {
33 | "bash": {
34 | "path": "/bin/bash"
35 | }
36 | },
37 | // notebook
38 | "notebook.formatOnSave.enabled": true,
39 | "notebook.codeActionsOnSave": {
40 | "notebook.source.fixAll": "explicit",
41 | "notebook.source.organizeImports": "explicit"
42 | },
43 | // python
44 | "[python]": {
45 | "editor.formatOnSave": true,
46 | "editor.defaultFormatter": "charliermarsh.ruff",
47 | "editor.codeActionsOnSave": {
48 | "source.fixAll": "explicit", // fix lint violations on-save
49 | "source.organizeImports": "explicit" // organize imports on-save
50 | }
51 | },
52 | "mypy-type-checker.args": [
53 | "--config=${workspaceFolder}/pyproject.toml"
54 | ],
55 | "python.defaultInterpreterPath": "/usr/local/bin/python",
56 | "python.analysis.typeCheckingMode": "basic",
57 | "python.analysis.inlayHints.functionReturnTypes": true,
58 | "python.analysis.inlayHints.variableTypes": true,
59 | "python.analysis.completeFunctionParens": true,
60 | // visibility
61 | "editor.bracketPairColorization.enabled": true,
62 | "editor.guides.bracketPairs": "active",
63 | // markdown
64 | "[markdown]": {
65 | "editor.wordWrap": "bounded",
66 | "editor.defaultFormatter": "esbenp.prettier-vscode"
67 | }
68 | },
69 | "extensions": [
70 | // python
71 | "ms-python.python",
72 | "ms-python.vscode-pylance",
73 | "ms-python.mypy-type-checker",
74 | "charliermarsh.ruff",
75 | "donjayamanne.python-extension-pack",
76 | // jupyter
77 | "ms-toolsai.jupyter",
78 | "ms-toolsai.jupyter-keymap",
79 | "ms-toolsai.jupyter-renderers",
80 | // git
81 | "mhutchie.git-graph",
82 | "eamodio.gitlens",
83 | "donjayamanne.git-extension-pack",
84 | // markdown
85 | "yzhang.markdown-all-in-one",
86 | "shd101wyy.markdown-preview-enhanced",
87 | "esbenp.prettier-vscode",
88 | // shell
89 | "mads-hartmann.bash-ide-vscode",
90 | "timonwong.shellcheck",
91 | "foxundermoon.shell-format",
92 | // visibility
93 | "mechatroner.rainbow-csv",
94 | "GrapeCity.gc-excelviewer",
95 | "janisdd.vscode-edit-csv",
96 | "monokai.theme-monokai-pro-vscode",
97 | "vscode-icons-team.vscode-icons",
98 | "MS-CEINTL.vscode-language-pack-ja",
99 | // other
100 | "github.copilot",
101 | "github.copilot-chat",
102 | "amazonwebservices.aws-toolkit-vscode",
103 | "amazonwebservices.amazon-q-vscode",
104 | "saoudrizwan.claude-dev"
105 | ]
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/.devcontainer/gpu-sagemaker/init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 763104351884.dkr.ecr.ap-northeast-1.amazonaws.com
3 |
--------------------------------------------------------------------------------
/.devcontainer/gpu-sagemaker/requirements.txt:
--------------------------------------------------------------------------------
1 | openai==1.76.0
2 | streamlit==1.44.1
3 |
--------------------------------------------------------------------------------
/.devcontainer/gpu-uv/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04
2 |
3 | # Install uv by copying the binary from the official distroless Docker image
4 | COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
5 |
6 | # Add non-root user
7 | ARG USERNAME=vscode
8 | ARG USER_UID=1000
9 | ARG USER_GID=$USER_UID
10 |
11 | # Install required packages and add non-root user
12 | RUN apt-get update && apt-get install -y \
13 | curl \
14 | unzip \
15 | sudo \
16 | git \
17 | && rm -rf /var/lib/apt/lists/* \
18 | && groupadd --gid $USER_GID $USERNAME \
19 | && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
20 | && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
21 | && chmod 0440 /etc/sudoers.d/$USERNAME
22 |
23 | # Install awscli v2
24 | RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
25 | && unzip awscliv2.zip \
26 | && ./aws/install \
27 | && rm -r aws \
28 | && rm awscliv2.zip
29 |
30 | # Switch to non-root user
31 | USER $USERNAME
32 |
33 | # Set working directory
34 | WORKDIR /home/$USERNAME/
35 |
--------------------------------------------------------------------------------
/.devcontainer/gpu-uv/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gpu-uv", // [Optional] Your project name here
3 | "build": {
4 | "dockerfile": "Dockerfile"
5 | },
6 | "workspaceFolder": "/workspace",
7 | "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
8 | "mounts": [
9 | "source=uv-cache,target=/root/.cache/uv,type=volume", // uv cache
10 | "source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached" // git config
11 | ],
12 | "runArgs": [
13 | "--gpus",
14 | "all",
15 | "--shm-size",
16 | "32g" // shared memory size
17 | ],
18 | "remoteEnv": {
19 | "UV_COMPILE_BYTECODE": "1",
20 | "UV_LINK_MODE": "copy",
21 | "UV_TORCH_BACKEND": "auto"
22 | },
23 | "postCreateCommand": "uv sync --frozen && . .venv/bin/activate && uv add pre-commit && uv run pre-commit install",
24 | // Configure tool-specific properties.
25 | "customizations": {
26 | // Configure properties specific to VS Code.
27 | "vscode": {
28 | "settings": {
29 | "terminal.integrated.profiles.linux": {
30 | "bash": {
31 | "path": "/bin/bash"
32 | }
33 | },
34 | // notebook
35 | "notebook.formatOnSave.enabled": true,
36 | "notebook.codeActionsOnSave": {
37 | "notebook.source.fixAll": "explicit",
38 | "notebook.source.organizeImports": "explicit"
39 | },
40 | // python
41 | "[python]": {
42 | "editor.formatOnSave": true,
43 | "editor.defaultFormatter": "charliermarsh.ruff",
44 | "editor.codeActionsOnSave": {
45 | "source.fixAll": "explicit", // fix lint violations on-save
46 | "source.organizeImports": "explicit" // organize imports on-save
47 | }
48 | },
49 | "mypy-type-checker.args": [
50 | "--config=${workspaceFolder}/pyproject.toml"
51 | ],
52 | "python.defaultInterpreterPath": "./.venv/bin/python",
53 | "python.analysis.typeCheckingMode": "basic",
54 | "python.analysis.inlayHints.functionReturnTypes": true,
55 | "python.analysis.inlayHints.variableTypes": true,
56 | "python.analysis.completeFunctionParens": true,
57 | // visibility
58 | "editor.bracketPairColorization.enabled": true,
59 | "editor.guides.bracketPairs": "active",
60 | // markdown
61 | "[markdown]": {
62 | "editor.wordWrap": "bounded",
63 | "editor.defaultFormatter": "esbenp.prettier-vscode"
64 | }
65 | },
66 | "extensions": [
67 | // python
68 | "ms-python.python",
69 | "ms-python.vscode-pylance",
70 | "ms-python.mypy-type-checker",
71 | "charliermarsh.ruff",
72 | "donjayamanne.python-extension-pack",
73 | // jupyter
74 | "ms-toolsai.jupyter",
75 | "ms-toolsai.jupyter-keymap",
76 | "ms-toolsai.jupyter-renderers",
77 | // git
78 | "mhutchie.git-graph",
79 | "eamodio.gitlens",
80 | "donjayamanne.git-extension-pack",
81 | // markdown
82 | "yzhang.markdown-all-in-one",
83 | "shd101wyy.markdown-preview-enhanced",
84 | "esbenp.prettier-vscode",
85 | // shell
86 | "mads-hartmann.bash-ide-vscode",
87 | "timonwong.shellcheck",
88 | "foxundermoon.shell-format",
89 | // visibility
90 | "mechatroner.rainbow-csv",
91 | "GrapeCity.gc-excelviewer",
92 | "janisdd.vscode-edit-csv",
93 | "monokai.theme-monokai-pro-vscode",
94 | "vscode-icons-team.vscode-icons",
95 | "MS-CEINTL.vscode-language-pack-ja",
96 | // other
97 | "github.copilot",
98 | "github.copilot-chat",
99 | "amazonwebservices.aws-toolkit-vscode",
100 | "amazonwebservices.amazon-q-vscode",
101 | "saoudrizwan.claude-dev"
102 | ]
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | #.idea/
161 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/astral-sh/uv-pre-commit
3 | rev: 0.6.17
4 | hooks:
5 | - id: uv-lock
6 | description: "Ensures that the uv.lock file is up-to-date"
7 |
8 | - repo: https://github.com/astral-sh/ruff-pre-commit
9 | rev: v0.11.7
10 | hooks:
11 | - id: ruff
12 | description: "Runs Ruff for Python code linting and static analysis"
13 | types_or: [python, pyi, jupyter]
14 | args: [--fix, --exit-non-zero-on-fix, --config=pyproject.toml]
15 | - id: ruff-format
16 | description: "Formats Python code using Ruff formatter"
17 | types_or: [python, pyi, jupyter]
18 | args: [--config=pyproject.toml]
19 |
20 | - repo: https://github.com/pre-commit/mirrors-mypy
21 | rev: v1.15.0
22 | hooks:
23 | - id: mypy
24 | description: "Performs type checking using mypy"
25 | types_or: [python, pyi, jupyter]
26 | args: [--config-file=pyproject.toml]
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2023 Renya Kujirada
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VSCode Dev Containers を利用した AWS EC2 上での開発環境構築手順
2 |
3 | 本リポジトリでは,Windows・Mac・Linux PC 上の Visual Studio Code IDE (VSCode) から AWS EC2 へリモート接続し,VSCode Dev Containers を利用して深層学習や LLM アプリケーション開発を効率良く行えるようにするための手順を示す.
4 |
5 | なお,本リポジトリはチーム開発時に,所属チームへクラウドネイティブで効率的な開発手法を導入することを目的としており,python コーディングにおける linter, formatter や VSCode extension,setting.json なども共通のものを利用するようにしている.
6 |
7 | ## TL;DR
8 |
9 | 以下の Tips を整理し,手順書としてまとめた.また,最小限の手順で済むよう,bat ファイルや shell スクリプトを用意している.
10 |
11 | - AWS Systems Manager (SSM) 経由で VSCode から EC2 にセキュアに SSH 接続する方法
12 | - チーム開発時の IDE として VSCode を利用し,uv,Ruff,mypy を共通的に利用する方法
13 | - AWS Deep Learning Containers Images 等をベースに Dev Containers 上で開発する方法
14 |
15 | ## 目次
16 |
17 | - [背景と課題](#背景と課題)
18 | - [目的](#目的)
19 | - [オリジナリティ](#オリジナリティ)
20 | - [前提](#前提)
21 | - [手順](#手順)
22 | - [手順の各ステップの詳細](#手順の各ステップの詳細)
23 | - [1. AWS CLI のインストールとセットアップ](#1-aws-cli-のインストールとセットアップ)
24 | - [2. SSM Session Manager plugin のインストール](#2-ssm-session-manager-plugin-のインストール)
25 | - [3. ローカルの VSCode に extension をインストール](#3-ローカルの-vscode-に-extension-をインストール)
26 | - [4. CloudFormation で EC2 を構築](#4-cloudformation-で-ec2-を構築)
27 | - [構築するリソース](#構築するリソース)
28 | - [EC2 の仕様について](#ec2-の仕様について)
29 | - [cf テンプレート利用時の入力パラメータについて](#cf-テンプレート利用時の入力パラメータについて)
30 | - [cf テンプレートの簡易説明](#cf-テンプレートの簡易説明)
31 | - [5. SSH の設定](#5-ssh-の設定)
32 | - [6. VSCode から EC2 インスタンスにログイン](#6-vscode-から-ec2-インスタンスにログイン)
33 | - [7. EC2 インスタンスに VSCode extension をインストール](#7-ec2-インスタンスに-vscode-extension-をインストール)
34 | - [8. 新規プロジェクトを作成](#8-新規プロジェクトを作成)
35 | - [9. Dev Containers を利用したコンテナの構築](#9-dev-containers-を利用したコンテナの構築)
36 | - [その他](#その他)
37 | - [インスタンスの起動・停止](#インスタンスの起動停止)
38 | - [コーディングガイドラインと開発環境の設定](#コーディングガイドラインと開発環境の設定)
39 | - [チームでの EC2 の運用・管理](#チームでの-ec2-の運用管理)
40 | - [Tips](#tips)
41 | - [VSCode Extension](#vscode-extension)
42 | - [Dockerfile](#dockerfile)
43 | - [CPU インスタンスで開発する場合](#cpu-インスタンスで開発する場合)
44 | - [CloudFormation Template の UserData の実行ログ](#cloudformation-template-の-userdata-の実行ログ)
45 | - [Ruff が動作しない場合](#ruff-が動作しない場合)
46 | - [Coding Agent の利用](#coding-agent-の利用)
47 | - [参考](#参考)
48 |
49 | ## 背景と課題
50 |
51 | 社内のローカル PC 上で深層学習モデルを開発する際,PoC 毎・メンバ毎に環境構築が必要で,時間を要してしまう課題がある.例えば,NVIDIA drivers や CUDA,PyTorch などのセットアップに苦労し,本来注力すべき本質的な開発タスクに十分なリソースを割くことができない.
52 |
53 | また,LLM API を利用したアプリケーションをチームで開発する際,社内プロキシが原因で開発が非効率になる課題がある.具体的には,API 実行時,SSL 証明書関連のエラーに苦労することが多い.加えて,リモートリポジトリの利用 (git push や pull) が制限されており,コードのバージョン管理や共有ができないことが多い.
54 |
55 | その他,チームの各メンバが利用する開発環境が統一化されていない場合,チームとしての開発効率が低下してしまう課題がある.特に,利用する OS や Python パッケージ管理ツール,Linter,Formatter が異なる場合,コードの一貫性が失われ,レビュープロセスが複雑化する.加え,環境の違いによりメンバ間でのコードの実行結果の再現性が損なわれる.
56 |
57 | AWS Cloud9 や SageMaker AI Studio Code Editor のようなクラウドネイティブ IDE を利用することで,上記の課題を解消できるが,いくつか課題がある.まず,ローカルの VSCode と比較すると,これらのサービスの利用には慣れや経験,知識が必須である.例えば,利用するマシンやそのストレージの実体の把握は,初学者には難しい.次に,ローカルの VSCode で利用可能な Extensions を全て利用できるわけではなく,開発者体験としては高いとは言えない.例えば,[Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) は利用できず,Docker コンテナの利用は CLI コマンド経由でしか行えない.これらの課題により,初学者や新規参画者には敷居が高く,即時参画には時間を要してしまう.
58 |
59 | ## 目的
60 |
61 | ローカル PC 上の VSCode から,VSCode Remote SSH により,SSM Session Manager Plugin 経由で EC2 インスタンスにログインし,EC2 上で開発できるようにする.その際,AWS Deep Learning AMIs を利用する.また,VSCode Dev Containers を利用し,開発環境をコンテナとして統一化する.これにより,開発環境の構築を自動化し,メンバ間でのコードの実行結果の再現性を担保する.また,社内プロキシ起因の課題を回避し,CodeCommit などのセキュアなリポジトリサービスを利用することができる.
62 |
63 | また,チーム開発で利用する IDE として VSCode を利用し,Python パッケージ管理ツール,Linter,Formatter,Extensions を統一化する.これにより,チームとしてのコーディングスタイルの統一化,コードの可動性や一貫性の向上を狙う.また,VSCode の Extensions である Dev Containers や Git Graph を利用することで,初学者には敷居の高い docker コマンドや git コマンドを利用せず,容易にコンテナ上での開発や,GUI ベースの Git 運用を行えるようにする.
64 |
65 |
66 |
67 | ## オリジナリティ
68 |
69 | 深層学習モデル開発,LLM API を利用したアプリケーション開発,SageMaker Pipelines 開発など,用途別に Dev Containers の環境を用意している.これらの環境では,基本的には Python パッケージ管理には uv,Formatter や Linter には Ruff を利用しており,git や aws cli が利用可能である.加え,Dev Containers を利用しているので Cline や Amazon Q Developer などの VSCode Extensions をコンテナ内でセキュアに利用することが可能である.
70 |
71 | | コンテナ名 | 用途 | 特徴 |
72 | | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
73 | | [cpu-uv](https://github.com/ren8k/aws-ec2-devkit-vscode/tree/main/.devcontainer/cpu-uv) | LLM API を利用したアプリケーション開発を想定 | - 軽量な Docker イメージを利用
- uv や Ruff を利用可能 |
74 | | [gpu-uv](https://github.com/ren8k/aws-ec2-devkit-vscode/tree/main/.devcontainer/gpu-uv) | 深層学習モデル開発 | - CUDA や cuDNN がセットアップ済み
- uv や Ruff を利用可能 |
75 | | [gpu-sagemaker](https://github.com/ren8k/aws-ec2-devkit-vscode/tree/main/.devcontainer/gpu-sagemaker) | SageMaker Pipeline の開発や Training Job の実行 | - [AWS Deep Learning Containers Images](https://github.com/aws/deep-learning-containers/blob/master/available_images.md) を利用
- PyTorch がプリインストール済み (pip) |
76 |
77 | ## 前提
78 |
79 | Windows,Linux 上には VSCode は install されているものとする.加え,AWS ユーザーは作成済みであり,以下のポリシーで定義される権限を最低限付与していることを想定している.なお,手順書中では,Windows でのセットアップに主眼を起き記述している.(Linux でも同様の手順で実施可能.)
80 |
81 |
82 | 最低限必要なポリシー
83 |
84 |
85 | ```json
86 | {
87 | "Version": "2012-10-17",
88 | "Statement": [
89 | {
90 | "Sid": "EC2InstanceManagement",
91 | "Effect": "Allow",
92 | "Action": ["ec2:StartInstances", "ec2:StopInstances"],
93 | "Resource": "arn:aws:ec2:*:*:instance/*"
94 | },
95 | {
96 | "Sid": "EC2DescribeAccess",
97 | "Effect": "Allow",
98 | "Action": "ec2:DescribeInstances",
99 | "Resource": "*"
100 | },
101 | {
102 | "Sid": "SSMSessionAccess",
103 | "Effect": "Allow",
104 | "Action": "ssm:StartSession",
105 | "Resource": [
106 | "arn:aws:ssm:*:*:document/AWS-StartSSHSession",
107 | "arn:aws:ec2:*:*:instance/*"
108 | ]
109 | },
110 | {
111 | "Sid": "SSMParameterAccess",
112 | "Effect": "Allow",
113 | "Action": "ssm:GetParameter",
114 | "Resource": "arn:aws:ssm:*:*:parameter/ec2/keypair/*"
115 | }
116 | ]
117 | }
118 | ```
119 |
120 |
121 |
122 |
123 | ## 手順
124 |
125 | 1. AWS CLI のインストールとセットアップ
126 | 2. SSM Session Manager plugin のインストール
127 | 3. ローカルの VSCode に extension をインストール
128 | 4. CloudFormation で EC2 を構築
129 | 5. SSH の設定
130 | 6. VSCode から EC2 インスタンスにログイン
131 | 7. EC2 インスタンスに VSCode extension をインストール
132 | 8. 新規プロジェクトを作成
133 | 9. Dev Containers を利用したコンテナの構築
134 |
135 | ## 手順の各ステップの詳細
136 |
137 | ### 1. AWS CLI のインストールとセットアップ
138 |
139 | 公式ドキュメント[^1-1] [^1-2]を参考に,AWS CLI をインストール,セットアップする.
140 |
141 | - [Windows 用の AWS CLI MSI インストーラ (64 ビット)](https://awscli.amazonaws.com/AWSCLIV2.msi) をダウンロードして実行する
142 | - インストール後,`aws --version`でバージョンが表示されれば OK
143 | - `aws configure`を実行し,AWS CLI の設定を行う
144 |
145 | ```
146 | AWS Access Key ID [None]: IAM ユーザーの作成時にダウンロードした csv ファイルに記載
147 | AWS Secret Access Key [None]: IAM ユーザーの作成時にダウンロードした csv ファイルに記載
148 | Default region name [None]: ap-northeast-1
149 | Default output format [None]: json
150 | ```
151 |
152 | - Zscaler などの社内プロキシを利用している場合は,`.aws/config`に以下を追記する.例えば,Zscaler を利用している場合は,以下のように CA 証明書のフルパスを記述する.CA 証明書のエクスポート方法は後述するので,必要があれば適宜参照されたい.
153 |
154 | ```
155 | ca_bundle = C:\path\to\zscalar_root_cacert.cer
156 | ```
157 |
158 |
159 | ※Zscaler CA 証明書のエクスポート方法
160 |
161 |
162 | Zscaler を利用してプロキシエージェント経由で通信を行う場合,Zscaler では SSL インスペクションの設定がなされているため,https 通信を行うときにルート証明書の情報が Zscaler のものに上書きされる.そのため,Zscaler のルート証明書を実行環境の証明書の信頼リストに登録しなければ https 通信が失敗する場合がある.
163 |
164 | **Windows の場合**
165 |
166 | 公式ドキュメント[^1-3]を参考に,Zscaler のルート証明書をエクスポートする.
167 |
168 | - コンピュータ証明書の管理 > 信頼されたルート証明機関 > 証明書
169 | - Zscalar Root CA を左クリック > すべてのタスク > エクスポート
170 | - 証明書のエクスポートウィザードで,次へ > Base 64 encoded X.509 を選択して次へ
171 | - 参照 > ディレクトリ・ファイル名を入力(ここではファイル名を`zscalar_root_cacert.cer`とする)> 次へ > 完了 > OK
172 |
173 | **macOS の場合**
174 |
175 | - Keychain を開き,システムチェーン -> システム の中にある Zscaler Root CA を右クリック
176 | - 「"Zscaler Root CA"を書き出す...」 を選択
177 | - `/path/to/zscalar_root_cacert.cer`などのファイル名で,任意のパスに保存
178 |
179 |
180 |
181 |
182 | ### 2. SSM Session Manager plugin のインストール
183 |
184 | 公式ドキュメント[^2-1]を参考に,SSM Session Manager plugin をインストールする.
185 |
186 | - [Session Manager プラグインのインストーラ](https://s3.amazonaws.com/session-manager-downloads/plugin/latest/windows/SessionManagerPluginSetup.exe)をダウンロードし実行する
187 |
188 | ### 3. ローカルの VSCode に extension をインストール
189 |
190 | [`./setup/vscode/vscode_local_setup_win.bat`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/vscode/vscode_local_setup_win.bat)を実行し,VSCode の extension を一括インストールする.Linux の場合は,[`./setup/vscode/vscode_local_setup_linux.sh`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/vscode/vscode_local_setup_linux.sh)を実行する.本バッチファイル,または shell の実行により,以下の extension がインストールされる.
191 |
192 | - vscode-remote-extensionpack: VSCode でリモート開発を行うための extension
193 | - aws-toolkit-vscode: AWS の各種サービスを VSCode から操作するための extension
194 | - ec2-farm: AWS アカウント内の EC2 インスタンスの状態を確認し,起動・停止・再起動を行うための extension
195 |
196 | ### 4. CloudFormation で EC2 を構築
197 |
198 | [`./setup/cf-template/cf-ec2.yaml`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/cf-template/cf-ec2.yaml)(cf テンプレート)を利用し,CloudFormation で EC2 を構築する.以下に実際に構築されるリソースと,cf テンプレートの簡易説明を行う.また,CloudFormation の詳細な実行方法は後述しているので,必要があれば適宜参照されたい.
199 |
200 | #### 構築するリソース
201 |
202 | - EC2
203 | - EC2 Key pair
204 | - Security Group
205 |
206 |
207 |
208 | #### EC2 の仕様について
209 |
210 | Deep Learning 用の AMI を利用しているため,以下が全てインストールされている状態で EC2 が構築される.詳細な仕様は,本 AWS ドキュメント[^4-1] [^4-2]を参照されたい.
211 |
212 | - Git
213 | - AWS CLI (v2 は `aws2`,v1 は `aws` コマンド)
214 | - Python (3.11)
215 | - Docker
216 | - NVIDIA Container Toolkit
217 | - NVIDIA driver (570.86.15)
218 | - CUDA, cuDNN (12.6)
219 | - PyTorch (2.6)
220 | - uv
221 |
222 | #### cf テンプレート利用時の入力パラメータについて
223 |
224 | | パラメータ名 | 説明 | デフォルト値 |
225 | | ----------------- | ------------------------------------- | ----------------------------------------------------------------------------- |
226 | | `EC2InstanceType` | 利用する EC2 のインスタンスタイプ | `g4dn.xlarge` (GPU インスタンス),`m5.large`などの CPU インスタンスも設定可能 |
227 | | `ImageId` | 利用する EC2 の AMI の種類 | `Deep Learning OSS Nvidia Driver AMI GPU PyTorch 2.6 (Ubuntu 22.04)` |
228 | | `SubnetId` | インターネット接続可能なサブネット ID | 指定必須(不明な場合は default VPC のパブリックサブネットを利用) |
229 | | `VolumeSize` | EC2 のボリュームサイズ | 100GB |
230 | | `VPCId` | 利用するサブネットが属する VPC の ID | 指定必須(不明な場合は default VPC を利用) |
231 |
232 | #### cf テンプレートの簡易説明
233 |
234 | - EC2 へのリモートアクセス・開発に必要と想定されるポリシーをアタッチしたロールは自動作成される.以下のポリシーをアタッチしている.
235 | - AmazonSSMManagedInstanceCore
236 | - AmazonS3FullAccess
237 | - AWSCodeCommitFullAccess
238 | - EC2InstanceProfileForImageBuilderECRContainerBuilds
239 | - AmazonSageMakerFullAccess
240 | - SecretsManagerReadWrite
241 | - AWSLambda_FullAccess
242 | - AmazonBedrockFullAccess
243 | - AmazonECS_FullAccess
244 | - セキュリティグループも自動作成しており,インバウンドは全てシャットアウトしている
245 | - SSH 接続で利用する Key Pair を作成している
246 | - EC2 インスタンス作成時,以下を自動実行している
247 | - git のアップグレード
248 | - uv のインストール
249 | - venv の仮想環境の activate
250 | - CloudFormation の出力部には,インスタンス ID と Key ID を出力している
251 | - 後述の shell で利用する
252 |
253 |
254 | ※CloudFormation 実行手順
255 |
256 |
257 | - [CloudFormation コンソール](https://console.aws.amazon.com/cloudformation/)を開き,スタックの作成を押下
258 | - テンプレートの指定 > テンプレートファイルのアップロード > ファイルの選択で上記で作成した yaml ファイルを指定し,次へを押下
259 | - [`./setup/cf-template/cf-ec2.yaml`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/cf-template/cf-ec2.yaml)を upload する
260 | - 任意の事情で upload が出来ない場合,テンプレートを S3 経由で利用するか,Application Composer を利用してテンプレートを利用すると良い (ローカル PC 上 or CloudShell 上で,cf テンプレートを S3 にアップロードする必要がある)
261 | - 任意のスタック名(利用者名などでよい)を入力後,以下のパラメータを設定・変更する
262 | - EC2InstanceType: インスタンスタイプ.デフォルトは g4dn.xlarge
263 | - ImageId: AMI の ID.デフォルトは Deep Learning AMI GPU PyTorch の ID
264 | - SubnetID: 利用するパブリックサブネットの ID(デフォルト VPC のパブリックサブネット ID 等で問題ない)
265 | - VPCId: 利用する VPC の ID(デフォルト VPC の ID 等で問題ない)
266 | - VolumeSize: ボリュームサイズ.デフォルトは 100GB
267 | - 適切な IAM Role をアタッチし,次へを押下(一時的に AdministratorAccess を付与したロールを利用しても良い)
268 | - 作成されるまで 5 分ほど待つ
269 |
270 |
271 |
272 |
273 | ### 5. SSH の設定
274 |
275 | [`./setup/get_aws_keypair/get_key_win.bat`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/ssh/ssh_setup_win.bat)を実行し,秘密鍵のダウンロードと`.ssh/config`の設定を自動実行する.Linux の場合は[`./setup/get_aws_keypair/get_key_linux.sh`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/ssh/ssh_setup_linux.sh)を実行すること.なお,実行前に,ソースコードの変数`KEY_ID`と`INSTANCE_ID`には CloudFormation の実行結果の各値を記述すること.また,複数台の EC2 を利用する場合,変数`HOST`や`SECRET_KEY`は一意になるように設定すること.
276 |
277 | ### 6. VSCode から EC2 インスタンスにログイン
278 |
279 | VSCode のリモート接続機能を利用して,SSM Session Manager Plugin 経由で EC2 インスタンスに SSH でログインする.以下,CloudFormation により EC2 の構築が完了している前提で説明する.
280 |
281 | - VSCode 上で,`F1`を押下し,`Remote-SSH: Connect to Host...`を選択
282 | - `~/.ssh/config`に記述したホスト名を選択(デフォルトでは`ec2`となっている)
283 | - Select the platform of the remtoe host "ec2" という画面が出たら`Linux`を選択すること
284 | - ※スタックの作成が完了しても,cf テンプレート内の UserData の shell 実行が終わるまで待つ必要があるため注意.(CloudFormation の実行完了後, 2, 3 分程度待つこと.UserData の実行ログは`/var/log/cloud-init-output.log`で確認できる.)
285 | - EC2 インスタンスにログイン後,インスタンス上に本リポジトリを clone する.
286 | - [`./setup/check_vm_env/check_cuda_torch.sh`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/check_vm_env/check_cuda_torch.sh)を実行し,EC2 インスタンス上で GPU や pytorch が利用可能であることを確認する.以下のような出力が表示されるはずである.
287 | - PyTorch を利用した MNIST の画像分類の学習を行うスクリプト[`./setup/check_vm_env/mnist_example/mnist.py`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/check_vm_env/mnist_example/mnist.py)を用意しているため,これを実行しても構わない.
288 |
289 | ```
290 | ==============check cuda==============
291 | nvcc: NVIDIA (R) Cuda compiler driver
292 | Copyright (c) 2005-2024 NVIDIA Corporation
293 | Built on Tue_Oct_29_23:50:19_PDT_2024
294 | Cuda compilation tools, release 12.6, V12.6.85
295 | Build cuda_12.6.r12.6/compiler.35059454_0
296 | ==============check gpu==============
297 | Sun Apr 27 04:59:53 2025
298 | +-----------------------------------------------------------------------------------------+
299 | | NVIDIA-SMI 570.86.15 Driver Version: 570.86.15 CUDA Version: 12.8 |
300 | |-----------------------------------------+------------------------+----------------------+
301 | | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
302 | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
303 | | | | MIG M. |
304 | |=========================================+========================+======================|
305 | | 0 Tesla T4 On | 00000000:00:1E.0 Off | 0 |
306 | | N/A 26C P8 9W / 70W | 1MiB / 15360MiB | 0% Default |
307 | | | | N/A |
308 | +-----------------------------------------+------------------------+----------------------+
309 |
310 | +-----------------------------------------------------------------------------------------+
311 | | Processes: |
312 | | GPU GI CI PID Type Process name GPU Memory |
313 | | ID ID Usage |
314 | |=========================================================================================|
315 | | No running processes found |
316 | +-----------------------------------------------------------------------------------------+
317 | ==============check torch==============
318 | if you exec at first time, you might wait for a while...
319 | torch.__version__: 2.6.0+cu126
320 | torch.cuda.is_available(): True
321 | ```
322 |
323 | ### 7. EC2 インスタンスに VSCode extension をインストール
324 |
325 | [`./setup/vscode/vscode_vm_setup.sh`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/vscode/vscode_vm_setup.sh)を実行し,EC2 インスタンス上で Git の初期設定と VSCode extension のインストール,VSCode の setting.json の設定を行う.なお,shell 実行時,Git の設定で利用する名前とメールアドレスをコマンドから入力すること.
326 |
327 | ### 8. 新規プロジェクトを作成
328 |
329 | [`./setup/make_new_project.sh`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/make_new_project.sh)を実行し,新規プロジェクトを作成する.新規プロジェクトは,本リポジトリ(テンプレート)を基に作成され,本リポジトリの一つ上の階層に作成される.
330 |
331 | `./setup/make_new_project.sh`を実行すると,プロジェクト名と,利用するコンテナ環境を選択するように求められる.プロジェクト名は任意の名前を入力すること.入力したプロジェクト名のディレクトリが新規プロジェクトとして作成される.また,コンテナ環境は,以下の 3 つから用途別に選択すること.各コンテナの詳細は後述する.
332 |
333 | - [cpu-uv](https://github.com/ren8k/aws-ec2-devkit-vscode/tree/main/.devcontainer/cpu-uv): LLM API を利用したアプリケーション開発を想定.
334 | - [gpu-uv](https://github.com/ren8k/aws-ec2-devkit-vscode/tree/main/.devcontainer/gpu-uv): GPU を利用した深層学習モデル開発を想定.
335 | - [gpu-sagemaker](https://github.com/ren8k/aws-ec2-devkit-vscode/tree/main/.devcontainer/gpu-sagemaker): SageMaker Pipeline の開発や SageMaker Training Job の実行を想定.
336 |
337 | `./setup/make_new_project.sh`の実行後,作成される新規プロジェクトは以下のようなディレクトリ構成となる.なお,以下では,入力したプロジェクト名を`sample-project`と仮定している.
338 |
339 | ```
340 | sample-project/
341 | ├── .devcontainer/ # 選択したDocker環境(cpu-uv、gpu-uv、gpu-sagemaker)の.devcontainerのみをコピー
342 | │ ├── Dockerfile
343 | │ └── devcontainer.json # プロジェクト名が設定済み
344 | ├── .git/ # Gitリポジトリ(初期化済み)
345 | ├── .gitignore
346 | ├── .pre-commit-config.yaml
347 | ├── README.md # プロジェクト名がタイトルに設定
348 | ├── pyproject.toml # プロジェクト名が設定済み
349 | ├── src/
350 | │ ├── __init__.py
351 | │ └── main.py
352 | └── uv.lock # プロジェクト名が設定済み
353 | ```
354 |
355 | `./setup/make_new_project.sh`の出力に従い,プロジェクトディレクトリに移動し,VSCode でディレクトリを開く.以下に出力の例を示す.
356 |
357 | ```
358 | [INFO] 次のステップ:
359 | 1. cd /path/to/sample-project
360 | 2. VS Code でディレクトリを開く
361 | 3. Dev Container でコンテナを起動する
362 | 4. 開発を開始!
363 | ```
364 |
365 | 参考に,各コンテナの説明を行う.
366 |
367 |
368 | cpu-uv
369 |
370 |
371 | - Python パッケージ管理には uv,Linter や Formatter には Ruff を利用している.
372 | - uv の基本的な利用方法は後述するが,詳細な利用方法は,公式ドキュメント [^8-1] や 技術ブログ [^8-2] [^8-3] を参照されたい.
373 | - Dockerfile 内部では,sudo を利用可能な一般ユーザーの作成および, AWS CLI v2 のインストールを行っている.
374 | - `uv add <パッケージ名>` でパッケージを install 可能.
375 | - `uv remove <パッケージ名>` でパッケージを uninstall 可能.
376 | - Python のバージョンを変更したい場合,`pyproject.toml`の`requires-python`を任意のバージョンに変更した後,`uv python pin <バージョン>` ,`uv sync`を実行する.
377 | - Ex. Python 3.11 を利用したい場合: `pyproject.toml`の`requires-python`を`">=3.11"`に変更し,`uv python pin 3.11 && uv sync`を実行する.
378 | - `uv run python`コマンド,または,venv の仮想環境を activate した状態で`python`コマンドを利用して,Python コードを実行可能.
379 | - 仮想環境の activate は`. .venv/bin/activate`コマンドで可能
380 | - pre-commit を利用し Git コミットする直前に Ruff や mypy による Lint,Format,型のチェックを行っている.
381 |
382 |
383 |
384 |
385 |
386 | gpu-uv
387 |
388 |
389 | - Python パッケージ管理には uv,Linter や Formatter には Ruff を利用している.
390 | - uv の基本的な利用方法は後述するが,詳細な利用方法は,公式ドキュメント [^8-1] や 技術ブログ [^8-2] [^8-3] を参照されたい.
391 | - Dockerfile 内部では,sudo を利用可能な一般ユーザーの作成および, AWS CLI v2 のインストールを行っている.
392 | - `uv add <パッケージ名>` でパッケージを install 可能.
393 | - `uv remove <パッケージ名>` でパッケージを uninstall 可能.
394 | - Python のバージョンを変更したい場合,`pyproject.toml`の`requires-python`を任意のバージョンに変更した後,`uv python pin <バージョン>` ,`uv sync`を実行する.
395 | - Ex. Python 3.11 を利用したい場合: `pyproject.toml`の`requires-python`を`">=3.11"`に変更し,`uv python pin 3.11 && uv sync`を実行する.
396 | - `uv run python`コマンド,または,venv の仮想環境を activate した状態で`python`コマンドを利用して,Python コードを実行可能.
397 | - 仮想環境の activate は`. .venv/bin/activate`コマンドで可能
398 | - PyTorch を install する場合,[`uv add torch torchvision`](https://docs.astral.sh/uv/guides/install-python/) を実行する.
399 | - pre-commit を利用し Git コミットする直前に Ruff や mypy による Lint,Format,型のチェックを行っている.
400 | - CUDA のバージョンは以下.
401 |
402 | ```
403 | $ nvcc -V
404 | nvcc: NVIDIA (R) Cuda compiler driver
405 | Copyright (c) 2005-2025 NVIDIA Corporation
406 | Built on Fri_Feb_21_20:23:50_PST_2025
407 | Cuda compilation tools, release 12.8, V12.8.93
408 | Build cuda_12.8.r12.8/compiler.35583870_0
409 | ```
410 |
411 |
412 |
413 |
414 |
415 | gpu-sagemaker
416 |
417 |
418 | - [AWS Deep Learning Containers Images](https://github.com/aws/deep-learning-containers/blob/master/available_images.md)を利用し,コンテナを構築している.[AWS Deep Learning Containers Images](https://github.com/aws/deep-learning-containers/blob/master/available_images.md)は,PyTorch, Tensorflow, MXNet などのフレームワークがプリインストールされたイメージ(SageMaker Training Job での実行環境イメージ)に加え,HuggingFace,StabilityAI のモデルの推論のためのイメージが提供されており,利用するイメージを適宜変更・カスタマイズすることで検証時の環境構築を効率化することができる.
419 | - Python パッケージ管理には pip,Linter や Formatter には Ruff を利用している.pip を利用している理由は,本 Docker イメージで pip 経由でプリインストールされている PyTorch などをクイックに利用することを想定しているためである.
420 | - Dockerfile 内部では, AWS CLI v2 のインストールを行っている.
421 | - devcontainer.json では以下の処理を行っている.
422 | - `initializeCommand`で, ECR へのログイン
423 | - `features`で,non-root ユーザーの作成
424 | - `remote`で,コンテナにおけるプロセス実行ユーザーを指定
425 | - [`./setup/check_vm_env/check_cuda_torch.sh`](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/setup/check_vm_env/check_cuda_torch.sh)を実行し,コンテナ内で GPU や PyTorch が利用可能であることを確認する.
426 |
427 | ```
428 | ==============check cuda==============
429 | nvcc: NVIDIA (R) Cuda compiler driver
430 | Copyright (c) 2005-2024 NVIDIA Corporation
431 | Built on Tue_Oct_29_23:50:19_PDT_2024
432 | Cuda compilation tools, release 12.6, V12.6.85
433 | Build cuda_12.6.r12.6/compiler.35059454_0
434 | ==============check gpu==============
435 | Sun Apr 27 04:57:38 2025
436 | +-----------------------------------------------------------------------------------------+
437 | | NVIDIA-SMI 570.86.15 Driver Version: 570.86.15 CUDA Version: 12.8 |
438 | |-----------------------------------------+------------------------+----------------------+
439 | | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
440 | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
441 | | | | MIG M. |
442 | |=========================================+========================+======================|
443 | | 0 Tesla T4 On | 00000000:00:1E.0 Off | 0 |
444 | | N/A 29C P8 13W / 70W | 1MiB / 15360MiB | 0% Default |
445 | | | | N/A |
446 | +-----------------------------------------+------------------------+----------------------+
447 |
448 | +-----------------------------------------------------------------------------------------+
449 | | Processes: |
450 | | GPU GI CI PID Type Process name GPU Memory |
451 | | ID ID Usage |
452 | |=========================================================================================|
453 | | No running processes found |
454 | +-----------------------------------------------------------------------------------------+
455 | ==============check torch==============
456 | if you exec at first time, you might wait for a while...
457 | torch.__version__: 2.6.0+cu126
458 | torch.cuda.is_available(): True
459 | ```
460 |
461 |
462 |
463 |
464 | ### 9. Dev Containers を利用したコンテナの構築
465 |
466 | Dev Containers を利用することで,GUI でコンテナを起動し,コンテナ内で容易に開発することができる.
467 |
468 | - VSCode 上で`F1`を押下し,`Dev Container: Reopen in Container`を選択する.
469 | - 初回のコンテナ構築時は,Docker イメージの pull に時間がかかるため,3~5 分程度待つ.
470 |
471 | 以下に利用時の注意点を示す.
472 |
473 | - コンテナ内での作業ディレクトリは`/workspace`であり,ローカルのプロジェクトディレクトリがマウントされている.
474 | - コンテナ内での作業ユーザー名は`vscode`であり,sudo 権限を持つ.
475 | - `devcontainer.json`の 2 行目の`name`には,手順 8 で入力したプロジェクト名が設定されている.
476 | - コンテナ構築後,remote repository の登録を行うこと.
477 | - VSCode 上で`F1`を押下し,`Git: Add Remote`を選択する.
478 | - リモートリポジトリの URL を入力する. (CodeCommit の https URL など)
479 | - リモート名を入力する.(`origin`などで良い)
480 | - リモートリポジトリの登録後,VSCode の左側の Git アイコンをクリックし,コミットやプッシュなどの操作が可能になる.
481 |
482 | ## その他
483 |
484 | ### インスタンスの起動・停止
485 |
486 | 開発開始時・終了時には,VSCode extension `EC2 Farm`経由で各々の EC2 インスタンスを起動・停止することが可能である.(AWS コンソールを開く必要はない.)
487 |
488 | ### コーディングガイドラインと開発環境の設定
489 |
490 | チーム開発において VSCode を利用するメリットは,Linter や Formatter をチームで共通化できる上,IDE の設定や利用する extension なども共通化することができる点である.これにより,チームメンバ間での利用するツールやコーディング上の認識齟齬は低減され,利便性の高い extension によって開発効率が向上する.また,pre-commit を利用し Git コミットする直前に Ruff や mypy による Lint,Format,型のチェックを行っている.詳細は,[./docs/coding-guidelines.md](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/docs/coding-guidelines.md)を参照されたい.
491 |
492 | ### チームでの EC2 の運用・管理
493 |
494 | インスタンスの切り忘れ防止のために,AWS Lambda を利用して,夜 12 時に全ての EC2 インスタンスを停止している.なお,運用サーバーなど特定のインスタンスは除外可能にできるようにしている.詳細は,[./docs/operation_ec2.md](https://github.com/Renya-Kujirada/aws-ec2-devkit-vscode/blob/main/docs/operation_ec2.md)を参照されたい.
495 |
496 | ### Tips
497 |
498 | #### VSCode Extension
499 |
500 | - Git 運用は,`Git Graph` を利用することで,GUI で行うことができる.
501 | - Docker コンテナ運用は,`Dev Containers` を利用することで,GUI で行うことができる.
502 | - EC2 インスタンスの起動や停止は,ローカルの VSCode にインストールした extension の`ec2-farm`で行える.
503 | - `ec2-farm`を開き,右クリックで EC2 を起動 or 停止が可能
504 | - リモートの Dev Container 環境への接続は,ローカルの VSCode にインストールした extension の`Project Manager`で行える.
505 | - Project Manager に登録したい Dev Container 環境を VSCode で起動
506 | - `Project Manager`を開き,Save Project (小さいディスクのアイコン) を選択し,Dev Container 環境を登録(任意の名前で保存可能)
507 | - 次回以降は,`ec2-farm`で EC2 を起動後,`Project Manager`に表示された Dev Container 名を選択することで,ssh 接続および Dev Container 起動と接続までが一度に実行可能
508 |
509 | #### Dockerfile
510 |
511 | - gpu-sagemaker において,Dockerfile の 1 行目で指定しているイメージを適宜変更することで,利用するモデルに応じた環境を容易に構築することができる.
512 | - ECR で利用可能なイメージは,[本リンク](https://github.com/aws/deep-learning-containers/blob/master/available_images.md)を参照されたい.
513 | - 例えば,Stable Diffusion 系列のモデルや,Stable Diffusion Web UI などを実行したい場合などは,以下のイメージを指定することで,簡単に環境を構築することができる.
514 | - `763104351884.dkr.ecr.ap-northeast-1.amazonaws.com/stabilityai-pytorch-inference:2.0.1-sgm0.1.0-gpu-py310-cu118-ubuntu20.04-sagemaker`
515 | - イメージによっては,non-root user が定義されている可能性がある.その場合,Dockerfile の 12~27 行目はコメントアウトすること(Dockerfile 内では明示的に non-root user を作成している)
516 | - non-root user を作成する際,Dockerfile ではなく,[`devcontainer.json`](https://github.com/ren8k/aws-ec2-devkit-vscode/blob/main/.devcontainer/gpu-sagemaker/devcontainer.json) の `features`の `common-utils` や`remoteUser`で設定することも可能である.詳細や使用例は,公式ドキュメント[^10-1]や公式リポジトリ[^10-2],技術ブログ[^10-3]を参照されたい.
517 | - gpu-sagemaker の [devcontainer.json](https://github.com/ren8k/aws-ec2-devkit-vscode/blob/main/.devcontainer/gpu-sagemaker/devcontainer.json) では,上記の方法で non-root user を作成している.
518 |
519 | #### CPU インスタンスで開発する場合
520 |
521 | - EC2 インスタンスのインスタンスタイプを,`m5.xlarge`などに変更する
522 | - 利用している AMI では GPU インスタンス以外は非推奨だが,問題なく動作した
523 | - gpu-sagemaker を利用する場合,`.devcontainer/devcontainer.json`の 9 行目と 14 行目をコメントアウトする
524 | - docker コマンドの引数`--gpus all`を除外する
525 | - コンテナのリビルドを実行する
526 |
527 | #### CloudFormation Template の UserData の実行ログ
528 |
529 | - EC2 インスタンスの以下のパスにログが出力される
530 | - `/var/log/cloud-init-output.log`
531 |
532 | #### Ruff が動作しない場合
533 |
534 | - VSCode 上で`F1`を押下し,`Python: Select Interpreter`を選択し,利用する Python のパスが適切に設定されているかを確認する.
535 |
536 | #### Coding Agent の利用
537 |
538 | - [`./setup/coding_agent`](https://github.com/ren8k/aws-ec2-devkit-vscode/blob/main/setup/coding_agent)ディレクトリでは,EC2 で Claude Code や Cline の設定を行うためのファイルを用意している.
539 |
540 | ## 参考
541 |
542 | [^1-1]: [AWS CLI の最新バージョンを使用してインストールまたは更新を行う](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)
543 | [^1-2]: [AWS CLI をセットアップする](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-quickstart.html)
544 | [^1-3]: [CA 証明書のエクスポート](https://help.zscaler.com/ja/deception/exporting-root-ca-certificate-active-directory-certificate-service)
545 | [^2-1]: [Windows での Session Manager プラグインのインストール](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/install-plugin-windows.html)
546 | [^4-1]: [AWS Deep Learning AMI GPU PyTorch 2.6 (Ubuntu 22.04)](https://aws.amazon.com/jp/releasenotes/aws-deep-learning-ami-gpu-pytorch-2-6-ubuntu-22-04/)
547 | [^4-2]: [AWS Deep Learning AMIs](https://docs.aws.amazon.com/ja_jp/dlami/latest/devguide/dlami-dg.pdf)
548 | [^8-1]: [uv: Managing dependencies](https://docs.astral.sh/uv/concepts/projects/dependencies/)
549 | [^8-2]: [uv だけで Python プロジェクトを管理する](https://zenn.dev/turing_motors/articles/594fbef42a36ee)
550 | [^8-3]: [uv から始まる Python 開発環境構築](https://zenn.dev/dena/articles/python_env_with_uv)
551 | [^10-1]: [Add a non-root user to a container](https://code.visualstudio.com/remote/advancedcontainers/add-nonroot-user)
552 | [^10-2]: [github repository: devcontainers / features](https://github.com/devcontainers/features/tree/main/src/common-utils)
553 | [^10-3]: [devcontainer で X11 forwarding 可能な環境を作る (あと uv と CUDA 環境も構築)](https://zenn.dev/colum2131/articles/c8b053b84ade7f)
554 |
--------------------------------------------------------------------------------
/docs/coding-guidelines.md:
--------------------------------------------------------------------------------
1 | # コーディングガイドラインと開発環境の設定
2 |
3 | VSCode を利用すれば,チーム内で Linter と Formatter の設定などを容易に統一することができる.特に,複数のエンジニアによるチーム開発において,リポジトリ内部でコーディングの一貫性を保つことは,可動性や品質の向上,チームメンバー間のコミュニケーション円滑化(認識・解釈齟齬の低下),引き継ぎ工数の削減の観点で重要である.
4 |
5 | 本リポジトリでは,上記を実現するために,Dev Containers 内で以下のツール・設定ファイルの共通利用を前提としている.なお,`./.devcontainer/devcontainer.json`ではデフォルトで以下を利用するための設定が記述されている.
6 |
7 | - Python package manager
8 | - Linter
9 | - Formatter
10 | - Type Hints
11 | - pre-commit
12 | - VSCode Extensions
13 | - settings.json
14 |
15 | ## Python package manager
16 |
17 | Python package manager は,Python ライブラリやパッケージのインストール,バージョン管理,依存関係の管理を行うためのツールである.本リポジトリでは,[uv](https://docs.astral.sh/uv/) を利用している.uv は,Rust で実装された Python のバージョンおよび Python パッケージを管理できるツールであり,pipenv や conda などの既存のツールと比べ,高速に実行できる.
18 |
19 | ## Linter
20 |
21 | Linter は,ソースコードを分析し,構文エラーやコーディングスタイルの問題,バグの可能性がある箇所を特定するツールである.本リポジトリでは,Python の Linter として [Ruff](https://docs.astral.sh/ruff/) を利用している.Ruff は,Rust で実装された Linter 兼 Formatte であり,Flake8 などの既存の Linter と比べ高速に実行できる.
22 |
23 | ## Formatter
24 |
25 | Formatter は,ソースコードのフォーマットを整理し,一貫したスタイルでコードを自動整形するツールである.本リポジトリでは,Python の Formatter として [Ruff](https://docs.astral.sh/ruff/) を利用している.
26 |
27 | ## Type Hints
28 |
29 | Type Hints は,特に静的型付け言語において,変数や関数の戻り値の型を指定するための構文である.本リポジトリでは,Python の Type Hints のチェックツールとして [mypy](https://mypy.readthedocs.io/en/stable/) を利用している.mypy は型アノテーションに基づきコードのバグを検知するツールである.
30 |
31 | ## pre-commit
32 |
33 | pre-commit は,Git のコミット前に自動的にコードのフォーマットや Lint チェックを実行するためのツールである.本リポジトリでは,以下の .pre-commit-config.yaml を利用し,以下の内容を実行している.
34 |
35 | - uv lock ファイルが更新されているか
36 | - Ruff による Lint,Format チェック
37 | - mypy による Type チェック
38 |
39 | ```yaml
40 | repos:
41 | - repo: https://github.com/astral-sh/uv-pre-commit
42 | rev: 0.6.17
43 | hooks:
44 | - id: uv-lock
45 | description: "Ensures that the uv.lock file is up-to-date"
46 |
47 | - repo: https://github.com/astral-sh/ruff-pre-commit
48 | rev: v0.11.7
49 | hooks:
50 | - id: ruff
51 | description: "Runs Ruff for Python code linting and static analysis"
52 | types_or: [python, pyi, jupyter]
53 | args: [--fix, --exit-non-zero-on-fix, --config=pyproject.toml]
54 | - id: ruff-format
55 | description: "Formats Python code using Ruff formatter"
56 | types_or: [python, pyi, jupyter]
57 | args: [--config=pyproject.toml]
58 |
59 | - repo: https://github.com/pre-commit/mirrors-mypy
60 | rev: v1.15.0
61 | hooks:
62 | - id: mypy
63 | description: "Performs type checking using mypy"
64 | types_or: [python, pyi, jupyter]
65 | args: [--config-file=pyproject.toml]
66 | ```
67 |
68 | ## VSCode extensions
69 |
70 | VSCode Extensions は,VSCode の機能を拡張するプラグインで,各種プログラミング言語のサポート,コードのデバッグ,リファクタリング,テキスト編集の強化,外部ツールの統合が可能である.本リポジトリでは,以下の VSCode Extensions を利用している.
71 |
72 | ### python
73 |
74 | - ms-python.python
75 | - ms-python.vscode-pylance
76 | - charliermarsh.ruff
77 | - ms-python.mypy-type-checker
78 | - donjayamanne.python-extension-pack
79 |
80 | ### jupyter
81 |
82 | - ms-toolsai.jupyter
83 | - ms-toolsai.jupyter-keymap
84 | - ms-toolsai.jupyter-renderers
85 |
86 | ### git
87 |
88 | - mhutchie.git-graph
89 | - eamodio.gitlens
90 | - donjayamanne.git-extension-pack
91 |
92 | ### markdown
93 |
94 | - yzhang.markdown-all-in-one
95 | - shd101wyy.markdown-preview-enhanced
96 |
97 | ### shell
98 |
99 | - mads-hartmann.bash-ide-vscode
100 | - timonwong.shellcheck
101 | - foxundermoon.shell-format
102 |
103 | ### visibility
104 |
105 | - mechatroner.rainbow-csv
106 | - GrapeCity.gc-excelviewer
107 | - janisdd.vscode-edit-csv
108 | - monokai.theme-monokai-pro-vscode
109 | - vscode-icons-team.vscode-icons
110 | - MS-CEINTL.vscode-language-pack-ja
111 |
112 | ### others
113 |
114 | - github.copilot
115 | - github.copilot-chat
116 | - aws-toolkit-vscode
117 | - amazonwebservices.amazon-q-vscode
118 | - saoudrizwan.claude-dev
119 |
120 | ## setting.json
121 |
122 | settings.json は,VSCode の設定ファイルで,エディタの挙動や見た目,拡張機能の設定などをカスタマイズできる.本リポジトリでは,以下の設定を利用し,Python コードの保存時に自動で Ruff や mypy を実行している.(`./.devcontainer/devcontainer.json`に記載がある.)
123 |
124 | ```json
125 | {
126 | "terminal.integrated.profiles.linux": {
127 | "bash": {
128 | "path": "/bin/bash"
129 | }
130 | },
131 | // notebook
132 | "notebook.formatOnSave.enabled": true,
133 | "notebook.codeActionsOnSave": {
134 | "notebook.source.fixAll": "explicit",
135 | "notebook.source.organizeImports": "explicit"
136 | },
137 | // python
138 | "[python]": {
139 | "editor.formatOnSave": true,
140 | "editor.defaultFormatter": "charliermarsh.ruff",
141 | "editor.codeActionsOnSave": {
142 | "source.fixAll": "explicit", // fix lint violations on-save
143 | "source.organizeImports": "explicit" // organize imports on-save
144 | }
145 | },
146 | "mypy-type-checker.args": ["--config=${workspaceFolder}/pyproject.toml"],
147 | "python.defaultInterpreterPath": "./.venv/bin/python",
148 | "python.analysis.typeCheckingMode": "basic",
149 | "python.analysis.inlayHints.functionReturnTypes": true,
150 | "python.analysis.inlayHints.variableTypes": true,
151 | "python.analysis.completeFunctionParens": true,
152 | // visibility
153 | "editor.bracketPairColorization.enabled": true,
154 | "editor.guides.bracketPairs": "active",
155 | // markdown
156 | "[markdown]": {
157 | "editor.wordWrap": "bounded",
158 | "editor.defaultFormatter": "esbenp.prettier-vscode"
159 | }
160 | }
161 | ```
162 |
163 | ## 参考
164 |
165 | - [mlops-starter-sklearn/docs/coding-guidelines.md](https://github.com/Azure/mlops-starter-sklearn/blob/main/docs/coding-guidelines.md)
166 | - [Python Coding Best Practices for Researchers](https://cyberagentailab.github.io/BestPracticesForPythonCoding/)
167 | - [uv だけで Python プロジェクトを管理する](https://zenn.dev/turing_motors/articles/594fbef42a36ee)
168 | - [Python パッケージ管理 [uv] 完全入門](https://speakerdeck.com/mickey_kubo/pythonpatukeziguan-li-uv-wan-quan-ru-men)
169 | - [深層学習を用いた実験における再現可能な環境構築](https://note.com/shunk031/n/n0f0e9e42b5aa)
170 | - [Anthropic で利用されているモダンな Python 開発のベストプラクティス](https://zenn.dev/yareyare/articles/d67aa75b37537c)
171 |
--------------------------------------------------------------------------------
/docs/operation_ec2.md:
--------------------------------------------------------------------------------
1 | # EC2 インスタンスの運用
2 |
3 | Cloud9 などで開発する場合,自動シャットダウン機能がデフォルトで提供されているため,インスタンスの消し忘れを防ぐことができる.しかし,VSCode Remote Development を利用して EC2 で開発する場合,自動シャットダウン機能が提供されていないため,消し忘れが発生しやすい.そこで,Lambda と EventBridge を利用し,夜 12 時に全ての EC2 インスタンスを停止させるように運用している.また,特定のインスタンスは停止の対象外にできるようにしている.
4 |
5 | ## 実行コード
6 |
7 | `./ops_ec2/lambda_function.py`を夜 12 時に定期実行している.コードでは,指定のリージョンのインスタンスを全て停止させている.
8 |
9 | ## 工夫点
10 |
11 | 環境変数`EXCLUDED_INSTANCE_IDS`に特定のインスタンスは停止の対象外にできるように工夫している.
12 |
13 | ```python
14 | # ./ops_ec2/lambda_function.py
15 | import boto3
16 | import os
17 |
18 | # env_var-> EXCLUDED_INSTANCE_IDS:
19 | excluded_instance_ids = os.environ['EXCLUDED_INSTANCE_IDS'].split(',')
20 | region = 'ap-northeast-1'
21 |
22 | def lambda_handler(event, context):
23 | ec2 = boto3.client('ec2', region_name=region)
24 |
25 | # Describe EC2 Instances
26 | instances = ec2.describe_instances()
27 |
28 | # Check the EC2 Instances ID and State
29 | for reservation in instances['Reservations']:
30 | for instance in reservation['Instances']:
31 | if instance['InstanceId'] not in excluded_instance_ids and instance['State']['Name'] == 'running':
32 | # Stop EC2 Instances that not equal to instance_id_excluded and in running state
33 | ec2.stop_instances(InstanceIds=[instance['InstanceId']])
34 | print('Stopping instance: ', instance['InstanceId'])
35 |
36 | return 'Complete stopping instances except ' + ', '.join(excluded_instance_ids)
37 |
38 | ```
39 |
--------------------------------------------------------------------------------
/img/cf-ec2-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ren8k/aws-ec2-devkit-vscode/0197763362d040eb0dfe7ef31cddded3877a9f5b/img/cf-ec2-architecture.png
--------------------------------------------------------------------------------
/img/vscode-ssm-ec2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ren8k/aws-ec2-devkit-vscode/0197763362d040eb0dfe7ef31cddded3877a9f5b/img/vscode-ssm-ec2.png
--------------------------------------------------------------------------------
/ops_ec2/lambda_function.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import boto3
4 |
5 | # env_var-> EXCLUDED_INSTANCE_IDS:
6 | excluded_instance_ids = os.environ['EXCLUDED_INSTANCE_IDS'].split(',')
7 | region = 'ap-northeast-1'
8 |
9 | def lambda_handler(event, context):
10 | ec2 = boto3.client('ec2', region_name=region)
11 |
12 | # Describe EC2 Instances
13 | instances = ec2.describe_instances()
14 |
15 | # Check the EC2 Instances ID and State
16 | for reservation in instances['Reservations']:
17 | for instance in reservation['Instances']:
18 | if instance['InstanceId'] not in excluded_instance_ids and instance['State']['Name'] == 'running':
19 | # Stop EC2 Instances that not equal to instance_id_excluded and in running state
20 | ec2.stop_instances(InstanceIds=[instance['InstanceId']])
21 | print('Stopping instance: ', instance['InstanceId'])
22 |
23 | return 'Complete stopping instances except ' + ', '.join(excluded_instance_ids)
24 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "app"
3 | version = "0.1.0"
4 | description = "Add your description here"
5 | readme = "README.md"
6 | requires-python = ">=3.13"
7 | dependencies = []
8 |
9 | [build-system]
10 | requires = ["hatchling"]
11 | build-backend = "hatchling.build"
12 |
13 | [tool.hatch.build.targets.wheel]
14 | packages = ["src"]
15 |
16 | [project.scripts]
17 | main = "src.main:main"
18 |
19 | # https://zenn.dev/turing_motors/articles/0f1a764d14f581
20 | [tool.ruff]
21 | exclude = [".git", ".mypy_cache", ".ruff_cache", ".venv", "third_party"]
22 | line-length = 160
23 | target-version = "py313"
24 |
25 | [tool.ruff.lint]
26 | fixable = ["ALL"]
27 | unfixable = []
28 | select = [
29 | "A", # flake8-builtin
30 | "B", # flake8-bugbear
31 | "E", # pycodestyle error
32 | "F", # Pyflakes
33 | "I", # isort
34 | "N", # pep8-naming
35 | "W", # pycodestyle warning
36 | "PL", # Pylint
37 | "UP", # pyupgrade
38 | ]
39 | ignore = [
40 | "B905", # Zip-without-explicit-strict
41 | "E501", # Line too long
42 | "F403", # Unable to detect undefined names
43 | "N812", # Lowercase imported as non-lowercase
44 | "N999", # Invalid module name
45 | "PLR0912", # Too many branches
46 | "PLR0913", # Too many arguments in function definition
47 | "PLR2004", # Magic value used in comparison
48 | ]
49 |
50 | [tool.ruff.format]
51 | quote-style = "double"
52 | line-ending = "auto"
53 |
54 | [tool.mypy]
55 | allow_redefinition = true
56 | allow_untyped_globals = false
57 | check_untyped_defs = true
58 | color_output = true
59 | disallow_incomplete_defs = true
60 | disallow_subclassing_any = false
61 | disallow_untyped_calls = false
62 | disallow_untyped_decorators = false
63 | disallow_untyped_defs = true
64 | error_summary = true
65 | ignore_missing_imports = true
66 | implicit_reexport = true
67 | namespace_packages = true
68 | no_implicit_optional = true
69 | pretty = true
70 | show_column_numbers = true
71 | show_error_codes = true
72 | show_error_context = true
73 | show_traceback = true
74 | strict = true
75 | warn_no_return = true
76 | warn_redundant_casts = true
77 | warn_return_any = true
78 | warn_unreachable = true
79 | warn_unused_configs = true
80 | warn_unused_ignores = false
81 |
--------------------------------------------------------------------------------
/setup/cf-template/cf-ec2.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: "2010-09-09"
2 | Description: AWS EC2 environment for remote connection from VSCode to experiment with deep learning. This file create EC2, IAMRole, Security Group, and EC2 Key pair.
3 | Parameters:
4 | ImageId:
5 | Description: Amazon Machine Image (AMI)
6 | Type: String
7 | Default: ami-09c1f9fce82b9f2af
8 | EC2InstanceType:
9 | Description: EC2 instance type on which IDE runs
10 | Type: String
11 | Default: g4dn.xlarge
12 | VolumeSize:
13 | Description: root volume size
14 | Type: String
15 | Default: 100
16 | VPCId:
17 | Description: VPC ID where the instance will be launched (For example, check your default vpc.)
18 | Type: String
19 | Default: vpc-XXXXXXXXXXXXXXXXX
20 | SubnetId:
21 | Description: Public subnet in vpc (For example, check your pucblic-subnet ip in default vpc.)
22 | Type: String
23 | Default: subnet-XXXXXXXXXXXXXXXXX
24 | Resources:
25 | EC2InstanceRole:
26 | Type: AWS::IAM::Role
27 | Properties:
28 | AssumeRolePolicyDocument:
29 | Version: "2012-10-17"
30 | Statement:
31 | - Effect: Allow
32 | Principal:
33 | Service:
34 | - ec2.amazonaws.com
35 | - sagemaker.amazonaws.com
36 | Action:
37 | - sts:AssumeRole
38 | ManagedPolicyArns:
39 | - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
40 | - arn:aws:iam::aws:policy/AmazonS3FullAccess
41 | - arn:aws:iam::aws:policy/AWSCodeCommitFullAccess
42 | - arn:aws:iam::aws:policy/EC2InstanceProfileForImageBuilderECRContainerBuilds
43 | - arn:aws:iam::aws:policy/AmazonSageMakerFullAccess
44 | - arn:aws:iam::aws:policy/SecretsManagerReadWrite
45 | - arn:aws:iam::aws:policy/AWSLambda_FullAccess
46 | - arn:aws:iam::aws:policy/AmazonBedrockFullAccess
47 | - arn:aws:iam::aws:policy/AmazonECS_FullAccess
48 | RoleName: !Sub ${AWS::StackName}-cf-remote-development-role
49 | Tags:
50 | - Key: Name
51 | Value: !Sub ${AWS::StackName}-cf-remote-development-role
52 | EC2InstanceProfile:
53 | Type: AWS::IAM::InstanceProfile
54 | Properties:
55 | Roles:
56 | - !Ref EC2InstanceRole
57 | NewKeyPair:
58 | Type: AWS::EC2::KeyPair
59 | Properties:
60 | KeyName: !Sub ${AWS::StackName}-cf-key
61 | Tags:
62 | - Key: Name
63 | Value: !Sub ${AWS::StackName}-cf-key
64 | EC2SecurityGroup:
65 | Type: AWS::EC2::SecurityGroup
66 | Properties:
67 | VpcId: !Ref VPCId
68 | GroupDescription: for remote development
69 | GroupName: !Sub ${AWS::StackName}-cf-sg
70 | SecurityGroupEgress:
71 | - CidrIp: 0.0.0.0/0
72 | FromPort: -1
73 | IpProtocol: -1
74 | ToPort: -1
75 | Tags:
76 | - Key: Name
77 | Value: !Sub ${AWS::StackName}-cf-sg
78 | EC2Instance:
79 | Type: AWS::EC2::Instance
80 | Properties:
81 | ImageId: !Ref ImageId
82 | InstanceType: !Ref EC2InstanceType
83 | KeyName: !Ref NewKeyPair
84 | NetworkInterfaces:
85 | - AssociatePublicIpAddress: true
86 | DeviceIndex: 0
87 | SubnetId: !Ref SubnetId
88 | GroupSet:
89 | - !GetAtt EC2SecurityGroup.GroupId
90 | IamInstanceProfile: !Ref EC2InstanceProfile
91 | BlockDeviceMappings:
92 | - DeviceName: /dev/sda1
93 | Ebs:
94 | VolumeType: gp3
95 | VolumeSize: !Ref VolumeSize
96 | DeleteOnTermination: "true"
97 | Encrypted: "false"
98 | UserData: !Base64 |
99 | #!/bin/bash
100 | export HOME=/home/ubuntu
101 |
102 | echo upgrade git
103 | sudo -E add-apt-repository ppa:git-core/ppa -y
104 | sudo apt-get update && sudo apt-get -y upgrade
105 | git config --global init.defaultBranch main
106 |
107 | echo setup git credential
108 | git config --global credential.helper '!aws codecommit credential-helper $@'
109 | git config --global credential.UseHttpPath true
110 |
111 | echo install uv
112 | curl -LsSf https://astral.sh/uv/install.sh | sh
113 |
114 | echo add pytorch venv activation to user profile
115 | echo "source /opt/pytorch/bin/activate" >> /home/ubuntu/.bashrc
116 | Tags:
117 | - Key: Name
118 | Value: !Sub ${AWS::StackName}-cf-ec2
119 | Outputs:
120 | InstanceId:
121 | Description: The Instance ID
122 | Value: !Ref EC2Instance
123 | InstanceRoleArn:
124 | Description: The Instance Role ARN
125 | Value: !GetAtt EC2InstanceRole.Arn
126 | KeyID:
127 | Description: The Key ID
128 | Value: !GetAtt NewKeyPair.KeyPairId
129 |
--------------------------------------------------------------------------------
/setup/check_vm_env/check_cuda_torch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # check cuda
4 | echo "==============check cuda=============="
5 | nvcc -V
6 |
7 | # check gpu
8 | echo "==============check gpu=============="
9 | nvidia-smi
10 |
11 | # check torch
12 | echo "==============check torch=============="
13 | echo "if you exec at first time, you might wait for a while..."
14 | python -c "import torch; print(f'torch.__version__: {torch.__version__}')"
15 | python -c "import torch; print(f'torch.cuda.is_available(): {torch.cuda.is_available()}')"
16 |
--------------------------------------------------------------------------------
/setup/check_vm_env/mnist_example/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017,
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/setup/check_vm_env/mnist_example/mnist.py:
--------------------------------------------------------------------------------
1 | # This code is cloned from https://github.com/pytorch/examples/blob/main/mnist/main.py
2 |
3 | from __future__ import print_function
4 | import argparse
5 | import torch
6 | import torch.nn as nn
7 | import torch.nn.functional as F
8 | import torch.optim as optim
9 | from torchvision import datasets, transforms
10 | from torch.optim.lr_scheduler import StepLR
11 |
12 |
13 | class Net(nn.Module):
14 | def __init__(self):
15 | super(Net, self).__init__()
16 | self.conv1 = nn.Conv2d(1, 32, 3, 1)
17 | self.conv2 = nn.Conv2d(32, 64, 3, 1)
18 | self.dropout1 = nn.Dropout(0.25)
19 | self.dropout2 = nn.Dropout(0.5)
20 | self.fc1 = nn.Linear(9216, 128)
21 | self.fc2 = nn.Linear(128, 10)
22 |
23 | def forward(self, x):
24 | x = self.conv1(x)
25 | x = F.relu(x)
26 | x = self.conv2(x)
27 | x = F.relu(x)
28 | x = F.max_pool2d(x, 2)
29 | x = self.dropout1(x)
30 | x = torch.flatten(x, 1)
31 | x = self.fc1(x)
32 | x = F.relu(x)
33 | x = self.dropout2(x)
34 | x = self.fc2(x)
35 | output = F.log_softmax(x, dim=1)
36 | return output
37 |
38 |
39 | def train(args, model, device, train_loader, optimizer, epoch):
40 | model.train()
41 | for batch_idx, (data, target) in enumerate(train_loader):
42 | data, target = data.to(device), target.to(device)
43 | optimizer.zero_grad()
44 | output = model(data)
45 | loss = F.nll_loss(output, target)
46 | loss.backward()
47 | optimizer.step()
48 | if batch_idx % args.log_interval == 0:
49 | print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
50 | epoch, batch_idx * len(data), len(train_loader.dataset),
51 | 100. * batch_idx / len(train_loader), loss.item()))
52 | if args.dry_run:
53 | break
54 |
55 |
56 | def test(model, device, test_loader):
57 | model.eval()
58 | test_loss = 0
59 | correct = 0
60 | with torch.no_grad():
61 | for data, target in test_loader:
62 | data, target = data.to(device), target.to(device)
63 | output = model(data)
64 | test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss
65 | pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
66 | correct += pred.eq(target.view_as(pred)).sum().item()
67 |
68 | test_loss /= len(test_loader.dataset)
69 |
70 | print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
71 | test_loss, correct, len(test_loader.dataset),
72 | 100. * correct / len(test_loader.dataset)))
73 |
74 |
75 | def main():
76 | # Training settings
77 | parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
78 | parser.add_argument('--batch-size', type=int, default=64, metavar='N',
79 | help='input batch size for training (default: 64)')
80 | parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
81 | help='input batch size for testing (default: 1000)')
82 | parser.add_argument('--epochs', type=int, default=14, metavar='N',
83 | help='number of epochs to train (default: 14)')
84 | parser.add_argument('--lr', type=float, default=1.0, metavar='LR',
85 | help='learning rate (default: 1.0)')
86 | parser.add_argument('--gamma', type=float, default=0.7, metavar='M',
87 | help='Learning rate step gamma (default: 0.7)')
88 | parser.add_argument('--no-cuda', action='store_true', default=False,
89 | help='disables CUDA training')
90 | parser.add_argument('--no-mps', action='store_true', default=False,
91 | help='disables macOS GPU training')
92 | parser.add_argument('--dry-run', action='store_true', default=False,
93 | help='quickly check a single pass')
94 | parser.add_argument('--seed', type=int, default=1, metavar='S',
95 | help='random seed (default: 1)')
96 | parser.add_argument('--log-interval', type=int, default=10, metavar='N',
97 | help='how many batches to wait before logging training status')
98 | parser.add_argument('--save-model', action='store_true', default=False,
99 | help='For Saving the current Model')
100 | args = parser.parse_args()
101 | use_cuda = not args.no_cuda and torch.cuda.is_available()
102 | use_mps = not args.no_mps and torch.backends.mps.is_available()
103 |
104 | torch.manual_seed(args.seed)
105 |
106 | if use_cuda:
107 | device = torch.device("cuda")
108 | elif use_mps:
109 | device = torch.device("mps")
110 | else:
111 | device = torch.device("cpu")
112 |
113 | train_kwargs = {'batch_size': args.batch_size}
114 | test_kwargs = {'batch_size': args.test_batch_size}
115 | if use_cuda:
116 | cuda_kwargs = {'num_workers': 1,
117 | 'pin_memory': True,
118 | 'shuffle': True}
119 | train_kwargs.update(cuda_kwargs)
120 | test_kwargs.update(cuda_kwargs)
121 |
122 | transform=transforms.Compose([
123 | transforms.ToTensor(),
124 | transforms.Normalize((0.1307,), (0.3081,))
125 | ])
126 | dataset1 = datasets.MNIST('../data', train=True, download=True,
127 | transform=transform)
128 | dataset2 = datasets.MNIST('../data', train=False,
129 | transform=transform)
130 | train_loader = torch.utils.data.DataLoader(dataset1,**train_kwargs)
131 | test_loader = torch.utils.data.DataLoader(dataset2, **test_kwargs)
132 |
133 | model = Net().to(device)
134 | optimizer = optim.Adadelta(model.parameters(), lr=args.lr)
135 |
136 | scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma)
137 | for epoch in range(1, args.epochs + 1):
138 | train(args, model, device, train_loader, optimizer, epoch)
139 | test(model, device, test_loader)
140 | scheduler.step()
141 |
142 | if args.save_model:
143 | torch.save(model.state_dict(), "mnist_cnn.pt")
144 |
145 |
146 | if __name__ == '__main__':
147 | main()
148 |
--------------------------------------------------------------------------------
/setup/coding_agent/claude-code/README.md:
--------------------------------------------------------------------------------
1 | # Claude Code セットアップ (on EC2)
2 |
3 | - `bash setup_claude_code.sh` を実行する
4 | - `source ~/.profile` を実行する
5 | - `claude` コマンドを実行する
6 | - terminal setup では,`2` を選択する (下図参照)
7 | - `1` を選択すると,[以下のエラー](https://github.com/anthropics/claude-code/issues/193)が出る.
8 | - `Error: Failed to install VSCode terminal Shift+Enter key binding`
9 |
10 | ```
11 | ╭──────────────────────────╮
12 | │ ✻ Welcome to Claude Code │
13 | ╰──────────────────────────╯
14 |
15 | Use Claude Code's terminal setup?
16 |
17 | For the optimal coding experience, enable the recommended settings
18 | for your terminal: Shift+Enter for newlines
19 |
20 | 1. Yes, use recommended settings
21 | ❯ 2. No, maybe later with /terminal-setup
22 |
23 | Enter to confirm · Esc to skip
24 |
25 | ```
26 |
--------------------------------------------------------------------------------
/setup/coding_agent/claude-code/setup_claude_code.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # ==============================================================================
4 | # Claude Code setup script for EC2
5 | # This script installs Node.js, Claude Code and adds configuration to ~/.profile
6 | # ==============================================================================
7 |
8 | set -e # Exit on error
9 |
10 | # ------------------------------------------------------------------------------
11 | # Step 1: Install Node.js via nvm
12 | # ------------------------------------------------------------------------------
13 | echo "Installing Node.js via nvm..."
14 |
15 | # Download and install nvm
16 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
17 |
18 | # Load nvm without restarting the shell
19 | \. "$HOME/.nvm/nvm.sh"
20 |
21 | # Install Node.js
22 | nvm install 22
23 |
24 | # Verify installation
25 | echo "Verifying Node.js installation..."
26 | node -v # Should display "v22.x.x"
27 | nvm current # Should display "v22.x.x"
28 | npm -v # Should display npm version
29 |
30 | # ------------------------------------------------------------------------------
31 | # Step 2: Install Claude Code
32 | # ------------------------------------------------------------------------------
33 | echo
34 | echo "Installing Claude Code..."
35 |
36 | npm install -g @anthropic-ai/claude-code
37 |
38 | if [ $? -eq 0 ]; then
39 | echo "Claude Code installed successfully"
40 | else
41 | echo "Failed to install Claude Code"
42 | exit 1
43 | fi
44 |
45 | # ------------------------------------------------------------------------------
46 | # Step 3: Configure Claude Code for AWS Bedrock
47 | # ------------------------------------------------------------------------------
48 | echo
49 | echo "Setting up Claude Code configuration..."
50 |
51 | # Check if the configuration already exists
52 | if grep -q "# Claude Code settings" ~/.profile 2>/dev/null; then
53 | echo "Claude Code settings already exist in ~/.profile"
54 | echo "Skipping configuration..."
55 | else
56 | # Append Claude Code settings to ~/.profile
57 | cat >> ~/.profile << 'EOF'
58 |
59 | # Claude Code settings
60 | export CLAUDE_CODE_USE_BEDROCK=1
61 | export ANTHROPIC_MODEL="us.anthropic.claude-opus-4-20250514-v1:0"
62 | # export ANTHROPIC_MODEL="us.anthropic.claude-sonnet-4-20250514-v1:0"
63 | export AWS_REGION="us-west-2"
64 | # export AWS_PROFILE="your-profile" # Uncomment if using specific AWS profile
65 | EOF
66 |
67 | echo "Claude Code settings added to ~/.profile"
68 | fi
69 |
70 | # ------------------------------------------------------------------------------
71 | # Step 4: Apply configuration
72 | # ------------------------------------------------------------------------------
73 | echo
74 | echo "Applying configuration..."
75 | source ~/.profile
76 |
77 | echo
78 | echo "Claude Code setup completed!"
79 | echo "Run 'claude' to start using Claude Code"
80 |
--------------------------------------------------------------------------------
/setup/coding_agent/cline/.clineignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | .coverage
3 | .mypy_cache
4 | .pytest_cache
5 | .ruff_cache
6 | .ipynb_checkpoints
7 | .venv
8 | *.egg-info
9 | .env
10 |
11 | # user setting
12 |
--------------------------------------------------------------------------------
/setup/coding_agent/cline/.clinerules:
--------------------------------------------------------------------------------
1 | # 基本設定
2 | - 出力言語:日本語
3 | - コードスタイル:PEP 8準拠
4 | - ドキュメント形式:Markdown
5 |
6 | # プロジェクト構造
7 | - AWS EC2上でVSCode Dev Containersを利用した開発環境のプロジェクト構造:
8 | ```
9 | - .devcontainer/ # Docker環境設定
10 | - docs/ # ドキュメント(コーディングガイドライン、運用手順など)
11 | - src/ # メインのソースコード
12 | - pyproject.toml # プロジェクト設定とパッケージ管理
13 | - uv.lock # パッケージのロックファイル
14 | ```
15 |
16 | # 技術スタック
17 | - 言語:Python 3.13
18 | - パッケージマネージャ:uv
19 | - Linter/Formatter:Ruff
20 | - 型チェッカー:mypy
21 | - フレームワーク:
22 | - 深層学習:PyTorch
23 | - AWS連携:boto3, sagemaker
24 | - CI/CD:pre-commit
25 | - コンテナ:Docker(Dev Containers経由)
26 |
27 | # 開発環境
28 | - AWS EC2(Ubuntu 22.04)
29 | - VSCode Remote SSH + Dev Containers
30 | - GPU環境:NVIDIA Driver 570.86.15, CUDA 12.6, cuDNN
31 |
32 | # 行動指針
33 | ## タスクの進め方
34 | 1. ユーザの依頼に対して、そのタスクをどのように実現できるか計画を立て、その計画をまずドキュメントにまとめます
35 | - ドキュメントは`outputs/cline`にユーザの依頼とそれに対する計画がわかるようにmarkdown形式でまとめます
36 | - 再度計画を立てると数$消費されるのを防ぐため、必ず計画はドキュメントにまとめてください
37 | - タスクの分割粒度ですが、各タスクごとにテストコードを記載できる程度の粒度でまとめてください
38 | - 注意:ユーザの指示の範囲内のみでタスクを考え、指示を超えた実装内容は絶対に含めないでください
39 | 2. ドキュメントが完成したら、計画の通りにタスクを実装します
40 | - タスクのスコープから外れる実装は絶対に行わないでください
41 | - タスクの実装が完了したら、必ずテストコードを記載してください
42 |
43 | ## コード実装
44 | - 既存のディレクトリ構造を遵守
45 | - uvを使用してパッケージ管理:`uv add/remove `
46 | - 仮想環境の使用:`uv run python`または`.venv/bin/activate`
47 |
48 | ## 静的解析
49 | - Ruffによるlint/format:プロジェクトルートの`pyproject.toml`設定に従う
50 | - mypyによる型チェック:プロジェクトルートの`pyproject.toml`設定に従う
51 |
52 | ## セキュリティ
53 | - 秘密情報(APIキー、パスワードなど)はコードに直接記述しない
54 | - AWS Systems Manager Parameter StoreまたはSecrets Managerを使用
55 | - SSH接続はSSM Session Manager経由で実施
56 |
57 | ## ドキュメント作成
58 | - README.mdは既存のフォーマットに従う
59 | - 技術的な詳細は`docs/`ディレクトリに配置
60 | - コメントは日本語で記述可能
61 |
62 | ## エラーハンドリング
63 | - AWS API呼び出し時は適切な例外処理を実装
64 | - ネットワークエラーやタイムアウトを考慮
65 | - エラーメッセージは日本語で分かりやすく記述
66 |
--------------------------------------------------------------------------------
/setup/coding_agent/cline/README.md:
--------------------------------------------------------------------------------
1 | # Cline セットアップ (on EC2)
2 |
3 | 以下のファイルをルートディレクトリに配置する.
4 |
5 | - `.clineignore`
6 | - `.clinerules`
7 |
8 | `.clinerules`については,各々が利用しやすいようにカスタマイズすること.(別に無くても良い.)
9 |
--------------------------------------------------------------------------------
/setup/make_new_project.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | # ========================================
6 | # Configuration
7 | # ========================================
8 |
9 | # Colors for output
10 | readonly RED='\033[0;31m'
11 | readonly GREEN='\033[0;32m'
12 | readonly YELLOW='\033[1;33m'
13 | readonly BLUE='\033[0;34m'
14 | readonly NC='\033[0m' # No Color
15 |
16 | # Docker environment options
17 | declare -A DOCKER_ENVS=(
18 | ["1"]="cpu-uv:CPU環境、uvパッケージマネージャ"
19 | ["2"]="gpu-uv:GPU環境、uvパッケージマネージャ"
20 | ["3"]="gpu-sagemaker:GPU環境、SageMaker用"
21 | )
22 |
23 | # Files to copy
24 | readonly CONFIG_FILES=(
25 | ".gitignore"
26 | ".pre-commit-config.yaml"
27 | "pyproject.toml"
28 | "uv.lock"
29 | )
30 |
31 | # Project name validation pattern
32 | readonly PROJECT_NAME_PATTERN='^[a-zA-Z0-9_-]+$'
33 |
34 | # ========================================
35 | # Utility Functions
36 | # ========================================
37 |
38 | print_info() {
39 | echo -e "${BLUE}[INFO]${NC} $1"
40 | }
41 |
42 | print_success() {
43 | echo -e "${GREEN}[SUCCESS]${NC} $1"
44 | }
45 |
46 | print_warning() {
47 | echo -e "${YELLOW}[WARNING]${NC} $1"
48 | }
49 |
50 | print_error() {
51 | echo -e "${RED}[ERROR]${NC} $1"
52 | }
53 |
54 | # ========================================
55 | # Setup Functions
56 | # ========================================
57 |
58 | setup_directories() {
59 | local script_path="${BASH_SOURCE[0]}"
60 | SCRIPT_DIR="$(cd "$(dirname "$script_path")" && pwd)"
61 | TEMPLATE_ROOT="$(dirname "$SCRIPT_DIR")"
62 | PARENT_DIR="$(dirname "$TEMPLATE_ROOT")"
63 | }
64 |
65 | # ========================================
66 | # Validation Functions
67 | # ========================================
68 |
69 | validate_project_name() {
70 | local name="$1"
71 |
72 | if [[ -z "$name" ]]; then
73 | print_error "プロジェクト名は必須です。"
74 | return 1
75 | fi
76 |
77 | if [[ ! "$name" =~ $PROJECT_NAME_PATTERN ]]; then
78 | print_error "プロジェクト名は英数字、ハイフン、アンダースコアのみ使用できます。"
79 | return 1
80 | fi
81 |
82 | local project_dir="$PARENT_DIR/$name"
83 | if [[ -d "$project_dir" ]]; then
84 | print_error "ディレクトリ '$name' は既に存在します。"
85 | return 1
86 | fi
87 |
88 | return 0
89 | }
90 |
91 | validate_docker_env_choice() {
92 | local choice="$1"
93 |
94 | if [[ -n "${DOCKER_ENVS[$choice]:-}" ]]; then
95 | return 0
96 | else
97 | print_error "1, 2, または 3 を選択してください。"
98 | return 1
99 | fi
100 | }
101 |
102 | # ========================================
103 | # Input Functions
104 | # ========================================
105 |
106 | prompt_project_name() {
107 | local project_name
108 |
109 | while true; do
110 | echo
111 | read -r -p "プロジェクト名を入力してください: " project_name
112 |
113 | if validate_project_name "$project_name"; then
114 | PROJECT_NAME="$project_name"
115 | PROJECT_DIR="$PARENT_DIR/$project_name"
116 | break
117 | fi
118 | done
119 | }
120 |
121 | prompt_docker_environment() {
122 | echo
123 | print_info "使用するDocker環境を選択してください:"
124 |
125 | local i
126 | for i in "${!DOCKER_ENVS[@]}"; do
127 | local env_info="${DOCKER_ENVS[$i]}"
128 | local env_name="${env_info%%:*}"
129 | local env_desc="${env_info#*:}"
130 | echo "$i) $env_name ($env_desc)"
131 | done | sort -n
132 |
133 | local choice
134 | while true; do
135 | read -r -p "選択 (1-3): " choice
136 |
137 | if validate_docker_env_choice "$choice"; then
138 | DOCKER_ENV="${DOCKER_ENVS[$choice]%%:*}"
139 | break
140 | fi
141 | done
142 | }
143 |
144 | confirm_settings() {
145 | print_info "選択された設定:"
146 | echo " プロジェクト名: $PROJECT_NAME"
147 | echo " Docker環境: $DOCKER_ENV"
148 | echo
149 |
150 | local reply
151 | read -r -p "この設定で続行しますか? (y/N): " reply
152 |
153 | if [[ ! $reply =~ ^[Yy]$ ]]; then
154 | print_info "キャンセルしました。"
155 | return 1
156 | fi
157 |
158 | return 0
159 | }
160 |
161 | # ========================================
162 | # Project Creation Functions
163 | # ========================================
164 |
165 | create_project_directory() {
166 | print_info "プロジェクトディレクトリを作成中..."
167 |
168 | if ! mkdir -p "$PROJECT_DIR"; then
169 | print_error "プロジェクトディレクトリの作成に失敗しました。"
170 | return 1
171 | fi
172 |
173 | return 0
174 | }
175 |
176 | copy_template_files() {
177 | print_info "必要なファイルをコピー中..."
178 |
179 | local error_occurred=false
180 |
181 | # Copy .devcontainer directory
182 | if ! cp -r "$TEMPLATE_ROOT/.devcontainer/$DOCKER_ENV" "$PROJECT_DIR/.devcontainer"; then
183 | print_error ".devcontainerディレクトリのコピーに失敗しました。"
184 | error_occurred=true
185 | fi
186 |
187 | # Copy src directory
188 | if ! cp -r "$TEMPLATE_ROOT/src" "$PROJECT_DIR/"; then
189 | print_error "srcディレクトリのコピーに失敗しました。"
190 | error_occurred=true
191 | fi
192 |
193 | # Copy configuration files
194 | local file
195 | for file in "${CONFIG_FILES[@]}"; do
196 | if ! cp "$TEMPLATE_ROOT/$file" "$PROJECT_DIR/"; then
197 | print_error "$file のコピーに失敗しました。"
198 | error_occurred=true
199 | fi
200 | done
201 |
202 | # Create README.md
203 | if ! echo "# $PROJECT_NAME" > "$PROJECT_DIR/README.md"; then
204 | print_error "README.mdの作成に失敗しました。"
205 | error_occurred=true
206 | fi
207 |
208 | if [[ "$error_occurred" == "true" ]]; then
209 | return 1
210 | fi
211 |
212 | return 0
213 | }
214 |
215 | update_project_files() {
216 | print_info "ファイルの内容を更新中..."
217 |
218 | local error_occurred=false
219 |
220 | # Update devcontainer.json name
221 | if ! sed -i "s/\"name\": \"$DOCKER_ENV\"/\"name\": \"$PROJECT_NAME\"/" \
222 | "$PROJECT_DIR/.devcontainer/devcontainer.json"; then
223 | print_error "devcontainer.jsonの更新に失敗しました。"
224 | error_occurred=true
225 | fi
226 |
227 | # Update pyproject.toml name
228 | if ! sed -i "s/name = \"app\"/name = \"$PROJECT_NAME\"/" \
229 | "$PROJECT_DIR/pyproject.toml"; then
230 | print_error "pyproject.tomlの更新に失敗しました。"
231 | error_occurred=true
232 | fi
233 |
234 | # Update uv.lock name
235 | if ! sed -i "s/name = \"app\"/name = \"$PROJECT_NAME\"/" \
236 | "$PROJECT_DIR/uv.lock"; then
237 | print_error "uv.lockの更新に失敗しました。"
238 | error_occurred=true
239 | fi
240 |
241 | # Fix initializeCommand path for gpu-sagemaker environment
242 | if [[ "$DOCKER_ENV" == "gpu-sagemaker" ]]; then
243 | if ! sed -i "s|\"initializeCommand\": \"bash \${localWorkspaceFolder}/.devcontainer/gpu-sagemaker/init.sh\"|\"initializeCommand\": \"bash \${localWorkspaceFolder}/.devcontainer/init.sh\"|" \
244 | "$PROJECT_DIR/.devcontainer/devcontainer.json"; then
245 | print_error "gpu-sagemaker用のinitializeCommandパスの更新に失敗しました。"
246 | error_occurred=true
247 | fi
248 | fi
249 |
250 | if [[ "$error_occurred" == "true" ]]; then
251 | return 1
252 | fi
253 |
254 | return 0
255 | }
256 |
257 | initialize_git_repository() {
258 | print_info "Gitリポジトリを初期化中..."
259 |
260 | if ! (cd "$PROJECT_DIR" && git init); then
261 | print_error "Gitリポジトリの初期化に失敗しました。"
262 | return 1
263 | fi
264 |
265 | return 0
266 | }
267 |
268 | cleanup_on_error() {
269 | if [[ -d "$PROJECT_DIR" ]]; then
270 | print_warning "エラーが発生したため、作成されたディレクトリを削除します..."
271 | rm -rf "$PROJECT_DIR"
272 | fi
273 | }
274 |
275 | show_completion_message() {
276 | print_success "プロジェクト '$PROJECT_NAME' が正常に作成されました!"
277 | print_info "プロジェクトディレクトリ: $PROJECT_DIR"
278 | echo
279 | print_info "次のステップ:"
280 | echo "1. cd $PROJECT_DIR"
281 | echo "2. VS Code でディレクトリを開く"
282 | echo "3. Dev Container でコンテナを起動する"
283 | echo "4. 開発を開始!"
284 | }
285 |
286 | # ========================================
287 | # Main Function
288 | # ========================================
289 |
290 | main() {
291 | # Setup environment
292 | setup_directories
293 |
294 | # Show header
295 | print_info "AWS EC2 DevKit Project Template Generator"
296 | echo "=========================================="
297 |
298 | # Get user inputs
299 | prompt_project_name
300 | prompt_docker_environment
301 |
302 | # Confirm settings
303 | if ! confirm_settings; then
304 | exit 0
305 | fi
306 |
307 | # Create project with error handling
308 | {
309 | create_project_directory &&
310 | copy_template_files &&
311 | update_project_files &&
312 | initialize_git_repository
313 | } || {
314 | print_error "プロジェクトの作成中にエラーが発生しました。"
315 | cleanup_on_error
316 | exit 1
317 | }
318 |
319 | # Show completion message
320 | show_completion_message
321 | }
322 |
323 | # ========================================
324 | # Script Entry Point
325 | # ========================================
326 |
327 | # Run main function if script is executed directly
328 | if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
329 | main "$@"
330 | fi
331 |
--------------------------------------------------------------------------------
/setup/ssh/ssh_setup_linux.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Set variables(cf output)
4 | KEY_ID="key-XXXXXXXXXXXXXXXXX"
5 | INSTANCE_ID="i-XXXXXXXXXXXXXXXXX"
6 | SECRET_KEY="ec2_secret_key.pem"
7 | KEY_PREFIX="/ec2/keypair"
8 | SSH_CONFIG="config"
9 | SSH_CONFIG_DIR="${HOME}/.ssh"
10 | SSH_CONFIG_PATH="${SSH_CONFIG_DIR}/${SSH_CONFIG}"
11 | SECRET_KEY_PATH="${SSH_CONFIG_DIR}/${SECRET_KEY}"
12 | HOST="ec2"
13 | USER="ubuntu"
14 |
15 | echo "Checking and creating .ssh directory if necessary..."
16 | if [ ! -d $SSH_CONFIG_DIR ]; then
17 | echo "Creating .ssh directory..."
18 | mkdir -p $SSH_CONFIG_DIR
19 | chmod 700 $SSH_CONFIG_DIR
20 | fi
21 |
22 | echo "Retrieving and saving the secret key..."
23 | aws ssm get-parameter --name $KEY_PREFIX/$KEY_ID --with-decryption --query "Parameter.Value" --output text >$SECRET_KEY_PATH
24 |
25 | echo "Setting permissions for the secret key..."
26 | chmod 600 $SECRET_KEY_PATH
27 |
28 | echo "Updating SSH configuration..."
29 | cat <>$SSH_CONFIG_PATH
30 | host $HOST
31 | HostName $INSTANCE_ID
32 | Port 22
33 | User $USER
34 | IdentityFile $SECRET_KEY_PATH
35 | TCPKeepAlive yes
36 | IdentitiesOnly yes
37 | ServerAliveInterval 60
38 | ForwardAgent yes
39 | ForwardX11 yes
40 | ProxyCommand bash -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
41 | EOF
42 |
43 | echo "Configuration complete."
44 |
--------------------------------------------------------------------------------
/setup/ssh/ssh_setup_win.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal enabledelayedexpansion
3 |
4 | REM Set variables(cf output)
5 | set "KEY_ID=key-XXXXXXXXXXXXXXXXX"
6 | set "INSTANCE_ID=i-XXXXXXXXXXXXXXXXX"
7 | set "SECRET_KEY=ec2_secret_key.pem"
8 | set "KEY_PREFIX=/ec2/keypair"
9 | set "SSH_CONFIG=config"
10 | set "SSH_CONFIG_DIR=%USERPROFILE%\.ssh"
11 | set "SSH_CONFIG_PATH=%SSH_CONFIG_DIR%\%SSH_CONFIG%"
12 | set "SECRET_KEY_PATH=%SSH_CONFIG_DIR%\%SECRET_KEY%"
13 | set "HOST=ec2"
14 | set "USER=ubuntu"
15 |
16 | REM If not exist "%SSH_CONFIG_DIR%" mkdir "%SSH_CONFIG_DIR%"
17 | if not exist "%SSH_CONFIG_DIR%" (
18 | echo Creating .ssh directory...
19 | mkdir "%SSH_CONFIG_DIR%"
20 | )
21 |
22 | REM Get key pair from parameter store and save to file
23 | echo Retrieving and saving the secret key...
24 | aws ssm get-parameter --name "%KEY_PREFIX%/%KEY_ID%" --with-decryption --query "Parameter.Value" --output text > "%SECRET_KEY_PATH%"
25 |
26 | REM Change permission
27 | echo Setting file permissions...
28 | icacls "%SECRET_KEY_PATH%" /inheritance:r
29 | icacls "%SECRET_KEY_PATH%" /grant "%USERNAME%:F"
30 |
31 | REM Postscript ssh config
32 | echo Updating SSH configuration...
33 | (
34 | echo host %HOST%
35 | echo HostName %INSTANCE_ID%
36 | echo Port 22
37 | echo User %USER%
38 | echo IdentityFile %SECRET_KEY_PATH%
39 | echo TCPKeepAlive yes
40 | echo IdentitiesOnly yes
41 | echo ServerAliveInterval 60
42 | echo ForwardAgent yes
43 | echo ForwardX11 yes
44 | echo ProxyCommand C:\Program Files\Amazon\AWSCLIV2\aws.exe ssm start-session --target %%h --document-name AWS-StartSSHSession --parameters "portNumber=%%p"
45 | ) >> "%SSH_CONFIG_PATH%"
46 |
47 | echo Configuration complete.
48 | endlocal
49 |
--------------------------------------------------------------------------------
/setup/vscode/vscode_local_setup_linux.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # install vscode extension
4 | code --install-extension ms-vscode-remote.vscode-remote-extensionpack
5 | code --install-extension amazonwebservices.aws-toolkit-vscode
6 | code --install-extension alefragnani.project-manager
7 | code --install-extension jabrythehutt.awsrd
8 | echo finish
9 |
--------------------------------------------------------------------------------
/setup/vscode/vscode_local_setup_win.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal enabledelayedexpansion
3 | cd %~dp0
4 |
5 | @REM set git credential helper (if you need to clone repos from aws codecommit)
6 | @REM git config --global credential.helper "!aws codecommit credential-helper $@"
7 | @REM git config --global credential.UseHttpPath true
8 |
9 | @REM install vscode extension
10 | code --install-extension ms-vscode-remote.vscode-remote-extensionpack &^
11 | code --install-extension amazonwebservices.aws-toolkit-vscode &^
12 | code --install-extension alefragnani.project-manager &^
13 | code --install-extension pengzhanzhao.ec2-farm
14 | echo finish
15 |
--------------------------------------------------------------------------------
/setup/vscode/vscode_settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // default terminal
3 | "terminal.integrated.profiles.linux": {
4 | "bash": {
5 | "path": "/bin/bash"
6 | }
7 | },
8 | // notebook
9 | "notebook.formatOnSave.enabled": true,
10 | "notebook.codeActionsOnSave": {
11 | "notebook.source.fixAll": "explicit",
12 | "notebook.source.organizeImports": "explicit"
13 | },
14 | // python
15 | "[python]": {
16 | "editor.formatOnSave": true,
17 | "editor.defaultFormatter": "charliermarsh.ruff",
18 | "editor.codeActionsOnSave": {
19 | "source.fixAll": "explicit", // fix lint violations on-save
20 | "source.organizeImports": "explicit" // organize imports on-save
21 | }
22 | },
23 | "mypy-type-checker.args": [
24 | "--ignore-missing-imports",
25 | "--disallow-untyped-defs"
26 | ],
27 | "python.defaultInterpreterPath": "/opt/pytorch/bin/python", // pytorch env in ec2-ml-ami
28 | "python.analysis.typeCheckingMode": "basic",
29 | "python.analysis.inlayHints.functionReturnTypes": true,
30 | "python.analysis.inlayHints.variableTypes": true,
31 | "python.analysis.completeFunctionParens": true,
32 | // visibility
33 | "editor.bracketPairColorization.enabled": true,
34 | "editor.guides.bracketPairs": "active",
35 | // markdown
36 | "[markdown]": {
37 | "editor.wordWrap": "bounded",
38 | "editor.defaultFormatter": "esbenp.prettier-vscode"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/setup/vscode/vscode_vm_setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # prompt for name and email
3 | read -p "Enter your name: " NAME
4 | read -p "Enter your email: " MAIL
5 |
6 | # git
7 | git config --global user.name "$NAME"
8 | git config --global user.email "$MAIL"
9 | git config --global core.editor vim
10 |
11 | # codecommit credential
12 | git config --global credential.helper '!aws codecommit credential-helper $@'
13 | git config --global credential.UseHttpPath true
14 |
15 | # install vscode extension
16 | ## python
17 | code --install-extension ms-python.python
18 | code --install-extension ms-python.vscode-pylance
19 | code --install-extension ms-python.mypy-type-checker
20 | code --install-extension charliermarsh.ruff
21 | code --install-extension donjayamanne.python-extension-pack
22 | ## docker
23 | code --install-extension ms-azuretools.vscode-docker
24 | ## jupyter
25 | code --install-extension ms-toolsai.jupyter
26 | code --install-extension ms-toolsai.jupyter-keymap
27 | code --install-extension ms-toolsai.jupyter-renderers
28 | ## git
29 | code --install-extension mhutchie.git-graph
30 | code --install-extension eamodio.gitlens
31 | code --install-extension donjayamanne.git-extension-pack
32 | ## markdown
33 | code --install-extension yzhang.markdown-all-in-one
34 | code --install-extension shd101wyy.markdown-preview-enhanced
35 | code --install-extension esbenp.prettier-vscode
36 | ## shell
37 | code --install-extension mads-hartmann.bash-ide-vscode
38 | code --install-extension timonwong.shellcheck
39 | code --install-extension foxundermoon.shell-format
40 | ## visibility
41 | code --install-extension mechatroner.rainbow-csv
42 | code --install-extension GrapeCity.gc-excelviewer
43 | code --install-extension janisdd.vscode-edit-csv
44 | code --install-extension monokai.theme-monokai-pro-vscode
45 | code --install-extension vscode-icons-team.vscode-icons
46 | code --install-extension MS-CEINTL.vscode-language-pack-ja
47 | ## other
48 | code --install-extension github.copilot
49 | code --install-extension github.copilot-chat
50 | code --install-extension amazonwebservices.aws-toolkit-vscode
51 | code --install-extension amazonwebservices.amazon-q-vscode
52 | code --install-extension saoudrizwan.claude-dev
53 |
54 | # vscode settings
55 | cp vscode_settings.json ~/.vscode-server/data/Machine/settings.json
56 |
57 | echo finish
58 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ren8k/aws-ec2-devkit-vscode/0197763362d040eb0dfe7ef31cddded3877a9f5b/src/__init__.py
--------------------------------------------------------------------------------
/src/main.py:
--------------------------------------------------------------------------------
1 | def main() -> None:
2 | print("Hello, World!")
3 |
4 |
5 | if __name__ == "__main__":
6 | main()
7 |
--------------------------------------------------------------------------------
/uv.lock:
--------------------------------------------------------------------------------
1 | version = 1
2 | revision = 1
3 | requires-python = ">=3.13"
4 |
5 | [[package]]
6 | name = "app"
7 | version = "0.1.0"
8 | source = { editable = "." }
9 |
--------------------------------------------------------------------------------