目录

  1. 1. 前言
  2. 2. 介绍
  3. 3. 安装
    1. 3.1. 更改数据存储位置
    2. 3.2. 更改镜像源
  4. 4. 运行
    1. 4.1. 验证安装是否成功
    2. 4.2. 查看镜像
    3. 4.3. 查看所有容器
    4. 4.4. 拉取镜像并启动容器
    5. 4.5. 运行镜像
    6. 4.6. 守护态运行
    7. 4.7. 镜像操作
    8. 4.8. 进入容器
    9. 4.9. 挂载目录
  5. 5. 基于CTF出题
    1. 5.1. 套模板
      1. 5.1.1. 拉取镜像
      2. 5.1.2. 出题
      3. 5.1.3. 封装镜像
      4. 5.1.4. 上传到自己的Hub
  6. 6. dockerfile
  7. 7. docker-compose
    1. 7.1. Quickstart
      1. 7.1.1. LAMP
      2. 7.1.2. python+redis
  8. 8. 实例
    1. 8.1. 从 Ubuntu 构建 lamp 环境
    2. 8.2. Docker上运行MongoDB
  9. 9. 调试
    1. 9.1. php
      1. 9.1.1. vscode 配置
      2. 9.1.2. phpstorm 配置
    2. 9.2. nodejs
    3. 9.3. python
      1. 9.3.1. Docker配置
        1. 9.3.1.1. 方法一:vscode自动识别web框架
        2. 9.3.1.2. 方法二:通用远程调试
      2. 9.3.2. vscode调试配置
        1. 9.3.2.1. 方法一:vscode自动识别web框架
        2. 9.3.2.2. 方法二:通用远程调试
      3. 9.3.3. vscode调试
    4. 9.4. java

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

Docker配置学习

2023/7/14 Basic Docker
  |     |   总文章阅读量:

前言

因为要搭环境复现漏洞等一系列原因,所以这里还是得把 Docker 学起来

参考:

菜鸟教程

安装参考csdn的文章

入门参考csdn的文章

官方文档: https://docs.docker.com/

https://treasure-house.randark.site/docs/DevSecOps/Containerization/Docker/Dockerfile-guide

https://yeasy.gitbook.io/docker_practice/container/attach_exec

介绍

by 菜鸟教程

Docker 是一个用于开发,交付和运行应用程序的开放平台。Docker 使您能够将应用程序与基础架构分开,从而可以快速交付软件。借助 Docker,您可以与管理应用程序相同的方式来管理基础架构。通过利用 Docker 的方法来快速交付,测试和部署代码,您可以大大减少编写代码和在生产环境中运行代码之间的延迟。

引用这里参考csdn文章的博主的理解:

1.可以快速搭建起程序运行所需要的环境。

2.可以打包程序和运行环境,避免因为缺乏某些库、或是环境变量设置的问题等导致程序无法运行。也就是说,解决了为什么在我的电脑上可以运行而在其他人电脑上不行的问题。

3.Docker只有需要的环境,比虚拟机占用的资源更少,操作也比虚拟机更简单。


安装

本人是在windows WSL2 上进行配置的

主要的安装流程可移步至菜鸟教程

这里提几个小tips

更改数据存储位置

windows默认安装在C盘,希望盘没逝

  1. 停止Docker服务

  2. 导出,备份数据到另一个文件夹

    wsl --export docker-desktop-data "E:\Docker\docker-desktop-data.tar"
  3. 删除原有数据

    wsl --unregister docker-desktop-data
  4. 更改数据存储盘并恢复数据

    wsl --import docker-desktop-data "E:\Docker" "E:\Docker\docker-desktop-data.tar" --version 2

    即将备份数据导入到新的虚拟盘,且指定虚拟盘的存放路径为E:\Docker,导入完成后在该目录下会存在一个ext4.vhdx的虚拟磁盘路径

    image-20230714172523867

    然后直接启动docker就行

更改镜像源

经典切换国内镜像

在设置的Docker Engine添加以下内容

"registry-mirrors": [
  "https://docker.mirrors.ustc.edu.cn",
  "http://f1361db2.m.daocloud.io",
  "https://registry.docker-cn.com"
],
"insecure-registries": [],
"debug": true,
"experimental": false

image-20230714173109899

阿里云要注册账号,这里就不演示了(


运行

验证安装是否成功

cmd里执行命令

docker version

image-20230714173446718

出现这些信息则说明安装完成


查看镜像

docker images

image-20230714173633117

REPOSITY代表所在仓库,TAG表示该镜像标签(版本)

对应的Docker Desktop图形化界面

image-20230714174109177


查看所有容器

docker ps -a

image-20230714173728072

CONTAINER ID表示该容器在Docker中的唯一ID,稍后的相关操作可以使用该ID进行,IMAGES表示该容器使用的镜像,NAMES表示我们给当前容器起的花名,与ID一样是唯一的

对应的Docker Desktop图形化界面

image-20230714174021993


拉取镜像并启动容器

从 docker 基础中可以了解到,docker 容器其实就是拉取相应的镜像并启动它,那就可以理解成虚拟机,但与虚拟机相比优势更大,可以把这个容器便是一个基于 Linux 的独立的”操作系统”了

这里以hello-world镜像为例

  1. 拉取镜像

    docker pull hello-world[:TAGS]

    image-20230714174759661

    这样就算拉取成功了

    对应的Docker Desktop图形化界面:

    搜索栏中查找,点击Pull即可

    image-20230714174913873

  2. 接着可以使用docker images或者直接在Docker Desktop图形化界面中查看本机中所有的镜像

  3. 最后启动一个容器实例

    docker run -itd --name test hello-world /hello

    image-20230714175536526

    返回了该容器的全称CONTAINER ID

    其中-itd表示以交互式终端切后台运行的模式启动即启动后容器仅在后台运行,不会进入容器实例

    –name test表示给该容器自定义的名字

    hello-world表示使用的镜像

    /hello对应执行的命令,交互式shell可以是/bin/bash

  4. 如果想进入该容器可以使用命令(如Ubuntu这类可以进入的镜像)

    docker exec -it 【CONTAINER ID】 /bin/bash

    注:在第三步执行的时候倘若还没有镜像则会自动拉取镜像

    CONTAINER ID可以少几位,会自己识别


运行镜像

docker run hello-world

image-20230714180142365

说明运行成功,这个方法会创建一个新的容器


守护态运行

更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d 参数来实现

$ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
hello world
hello world
hello world
hello world

$ docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a

不加 -d 的情况会使容器把 STDOUT 打印到宿主机上,使用 -d 后要查看的话可以用 docker logs


镜像操作

docker rm <container_id_or_name>
docker rmi [OPTIONS] IMAGE [IMAGE...]

docker save -o image.tar image:latest # 保存镜像
docker load < image.tar	

进入容器

有两种方法进入,attachexec

$ docker run -dit ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550

$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
243c32535da7        ubuntu:latest       "/bin/bash"         18 seconds ago      Up 17 seconds                           nostalgic_hypatia

$ docker attach 243c
root@243c32535da7:/#

使用 attach 的情况下,如果从这个 stdin 中 exit,会导致容器的停止

使用 exec 则不会

$ docker run -dit ubuntu
69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6

$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
69d137adef7a        ubuntu:latest       "/bin/bash"         18 seconds ago      Up 17 seconds                           zealous_swirles

$ docker exec -i 69d1 bash
ls
bin
boot
dev
...

$ docker exec -it 69d1 bash
root@69d137adef7a:/#

挂载目录

命令行中查看容器挂载的主机目录

docker inspect 容器ID或容器名 | grep -A 30 Mounts

基于CTF出题

套模板

对于基础的 PHP 题目而言,我们可以通过拉取已有的 lamp 容器的方式,替换其中的 php 文件即可

记录了一次出题过程:

拉取镜像

先拉一个题目环境下来

这里拉了一个vaalacat/push_f12下来

启动镜像

出题

先在本地编写题目代码

<!DOCTYPE html>
<html>
    <head>
        <title>FTwelve</title>
        <!--flag{ctf web St@rt!}-->
    </head>
    <body>
        <h1>这是什么?</h1>
        <p>你说的对,但是web是由...</p>
        <p>中间忘了</p>
        <p>后面忘了</p>
        <p>总之就是逐步发掘phpinfo()的真相(</p>
        <!--Huh?-->
        <?php
        phpinfo();
        ?>
    </body>
</html>

然后拷贝到容器中

docker cp ./ 35007d4:/var/www/html

image-20230802120100773

封装镜像

把这个容器封装成一个新的镜像

docker commit 35007d my_f12

上传到自己的Hub

注册一个账号

然后

docker tag my_f12 c1oudfl0w0/my_f12:tags

然后就能 push 到自己的仓库了


dockerfile

Dockerfile 文件本身可以看作是编译控制流的一种,通过相关语句可以同时最终 docker 镜像的编译成果。在 Dockerfile 中,可以实现命令执行,文件传输,环境变量控制,标签控制,容器入口点控制等等

# 文件传递
ADD
COPY

# 命令执行
RUN

# 容器入口点控制
CMD
ENTRYPOINT

# 标签控制
TAG

docker-compose

主要用于定义和运行多容器 Docker 应用程序

参考: https://docs.docker.com/compose/gettingstarted/

命令:

docker compose up
docker compose up -d	# 后台启动所有服务
docker compose stop
docker compose down	# 停止并删除所有服务容器、网络和卷

Quickstart

LAMP

注意:php 8.1-apache 及之后的版本换源的位置迁移到了 /etc/apt/sources.list.d/debian.sources;php 8.0-apache 及之前到版本换源的位置在 /etc/apt/sources.list


python+redis

搭建一个 python + redis 的服务,把本地的 app.py 映射到容器中方便修改

app/app.py

import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count()
    return f'Hello World! I have been seen {count} times.\n'

app/requirements.txt

flask
redis

app/Dockerfile

FROM python:3.10-alpine
WORKDIR /app
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run", "--debug"]

docker-compose.yml

services:
  web:
    build: ./app
    ports:
      - "25000:5000"
    volumes:
      - ./app:/app
  redis:
    image: "redis:alpine"

综合例:

version: '3.8'

# 定义网络配置
networks:
  ctf-frontend:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: ctf-front
    ipam:
      driver: default
      config:
        - subnet: 172.20.0.0/24
          gateway: 172.20.0.1
  ctf-backend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.21.0.0/24

# 数据卷配置
volumes:
  mysql_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ./data/mysql
  redis_data:
    driver: local
  challenge_uploads:
    driver: local

# 服务定义
services:
  # Web前端服务
  web-frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
      args:
        BUILD_ENV: production
    image: ctf-frontend:latest
    container_name: ctf-web-frontend
    hostname: ctf-web
    networks:
      ctf-frontend:
        ipv4_address: 172.20.0.10
    ports:
      - "80:80"
      - "443:443"
    expose:
      - "8080"
    volumes:
      - ./frontend/app:/app:ro
      - ./ssl:/etc/nginx/ssl:ro
      - challenge_uploads:/uploads
    environment:
      - ENVIRONMENT=production
      - DEBUG=false
      - BACKEND_API_URL=http://api-backend:8000
      - REDIS_URL=redis://redis-cache:6379
    env_file:
      - ./config/web.env
    depends_on:
      - api-backend
      - redis-cache
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "1.0"
        reservations:
          memory: 256M
          cpus: "0.5"
    privileged: false
    read_only: true
    tmpfs:
      - /tmp:size=100m,mode=1777
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE

  # API后端服务
  api-backend:
    build: ./backend
    image: ctf-backend:latest
    container_name: ctf-api-backend
    hostname: ctf-api
    networks:
      ctf-frontend:
      ctf-backend:
        ipv4_address: 172.21.0.20
    ports:
      - "8000:8000"
    volumes:
      - ./backend/src:/app:ro
      - ./backend/config:/config:ro
    environment:
      - DATABASE_URL=mysql://ctf_user:${MYSQL_PASSWORD}@mysql-db:3306/ctf
      - REDIS_HOST=redis-cache
      - REDIS_PORT=6379
      - SECRET_KEY=${BACKEND_SECRET_KEY}
    env_file:
      - ./config/backend.env
    depends_on:
      mysql-db:
        condition: service_healthy
      redis-cache:
        condition: service_started
    restart: on-failure
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1"]
      interval: 20s
      timeout: 5s
      retries: 5
    stdin_open: false
    tty: false
    mem_limit: 1g
    cpus: 2
    labels:
      - "ctf.service.type=api"
      - "ctf.challenge.category=web"

  # MySQL数据库服务
  mysql-db:
    image: mysql:8.0
    container_name: ctf-mysql-db
    hostname: ctf-mysql
    networks:
      ctf-backend:
        ipv4_address: 172.21.0.30
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./database/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=ctf
      - MYSQL_USER=ctf_user
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_INNODB_BUFFER_POOL_SIZE=256M
    command:
      - --default-authentication-plugin=mysql_native_password
      - --innodb-buffer-pool-size=256M
      - --max-connections=1000
    restart: always
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 10s
      timeout: 5s
      retries: 10
    security_opt:
      - seccomp:unconfined
    ulimits:
      nproc: 65535
      nofile:
        soft: 20000
        hard: 40000

  # Redis缓存服务
  redis-cache:
    image: redis:7-alpine
    container_name: ctf-redis-cache
    hostname: ctf-redis
    networks:
      ctf-backend:
        ipv4_address: 172.21.0.40
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
      - ./redis/redis.conf:/etc/redis/redis.conf:ro
    command: redis-server /etc/redis/redis.conf --requirepass ${REDIS_PASSWORD}
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD}
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

  # CTF题目容器 - Pwn挑战
  pwn-challenge:
    build:
      context: ./challenges/pwn
      dockerfile: Dockerfile.pwn
    image: ctf-pwn-challenge:latest
    container_name: ctf-pwn-challenge
    networks:
      ctf-backend:
        ipv4_address: 172.21.0.50
    ports:
      - "9999:9999"
    expose:
      - "9999"
    volumes:
      - ./challenges/pwn/bin:/challenge:ro
    environment:
      - CHALLENGE_PORT=9999
      - CHALLENGE_NAME=pwn_binary
      - FLAG=${PWN_FLAG}
    restart: unless-stopped
    cap_add:
      - SYS_PTRACE
    security_opt:
      - apparmor:unconfined
    privileged: false
    labels:
      - "ctf.challenge.type=pwn"
      - "ctf.difficulty=hard"

  # CTF题目容器 - Web挑战
  web-challenge:
    build: ./challenges/web
    image: ctf-web-challenge:latest
    container_name: ctf-web-challenge
    networks:
      ctf-backend:
        ipv4_address: 172.21.0.60
    ports:
      - "8081:80"
    volumes:
      - ./challenges/web/src:/var/www/html:ro
    environment:
      - FLAG=${WEB_FLAG}
      - DB_HOST=mysql-db
    depends_on:
      - mysql-db
    restart: unless-stopped
    labels:
      - "ctf.challenge.type=web"
      - "ctf.difficulty=medium"

  # 监控服务
  monitor:
    image: docker:latest
    container_name: ctf-monitor
    networks:
      ctf-frontend:
      ctf-backend:
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./monitor/scripts:/scripts:ro
    command: ["sh", "/scripts/monitor.sh"]
    restart: unless-stopped
    depends_on:
      - web-frontend
      - api-backend

实例

从 Ubuntu 构建 lamp 环境

# 使用 Ubuntu 官方镜像
FROM ubuntu:20.04

# 设置环境变量以避免交互式安装提示
ENV DEBIAN_FRONTEND=noninteractive

# 使用中科大源替换默认源
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && \
    sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list

# 更新软件包列表并安装必要的软件
RUN apt-get update && apt-get install -y \
    apache2 \
    mysql-server \
    php \
    libapache2-mod-php \
    php-mysql \
    openssh-server \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# 配置 SSH 服务
RUN mkdir /var/run/sshd
RUN echo 'root:root' | chpasswd
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# 复制本地文件到容器中
COPY ./src /var/www/html

# 设置 Apache 和 MySQL 的权限
RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 755 /var/www/html

# 暴露端口:80 (HTTP) 和 22 (SSH)
EXPOSE 80 22

# 启动服务
CMD service mysql start && \
    service apache2 start && \
    /usr/sbin/sshd -D

Docker上运行MongoDB

安装就不多说了

运行容器

docker run -itd --name mongo -p 27017:27017 mongo --auth
  • -p 27017:27017 :映射容器服务的27017端口到宿主机的27017端口。外部可以直接通过宿主机ip:27017 访问到 mongo 的服务
  • --auth:需要密码才能访问容器服务

添加用户(MongoDB > 6.0)

docker exec -it mongo mongosh admin

设置密码

db.createUser({ user:'admin',pwd:'123456',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]});

尝试使用上面创建的用户信息进行连接

db.auth('admin', '123456')

image-20230820180654147


调试

php

vscode 配置

参考:https://depp.wang/2022/12/28/debug-docker-php-code-in-vscode/

  1. PHP 容器中安装 xdebug 依赖
# 查看 xdebug 是否已安装
php -m | grep xdebug 
# 安装
pecl install xdebug
# 开启 xdebug
docker-php-ext-enable xdebug
# 重启容器
docker restart <your-php-container-name>
  1. 修改 xdebug 配置

    容器内 /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

zend_extension=xdebug
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_port = 9003
xdebug.discover_client_host = true
xdebug.client_host = host.docker.internal
xdebug.remote_host = host.docker.internal

修改后重启容器

  1. vscode配置.vscode/launch.json
{
 // Use IntelliSense to learn about possible attributes.
 // Hover to view descriptions of existing attributes.
 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 "version": "0.2.0",
 "configurations": [
   {
	 "name": "Listen for Xdebug",
	 "type": "php",
	 "request": "launch",
	 "port": 9003,
	 "pathMappings": {
	// 容器映射本地
	   "/data/project/material/": "${workspaceFolder}" // /data/project/material/ 路径是自己 PHP Docker 的 WorkingDir
	   }
   }
 ]
}

这里的mapping可以为多个文件之间的mapping,前面为容器中的地址后面为本地代码的地址

phpstorm 配置

参考 https://blog.51cto.com/u_16125110/14125181

  1. 同上,容器中安装 xdebug 依赖
  2. php -i | grep xdebug 查找并修改配置文件,修改后重启服务
zend_extension=xdebug
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_port = 9003
xdebug.discover_client_host = true
xdebug.client_host = host.docker.internal
xdebug.remote_host = host.docker.internal
xdebug.idekey = "phpstorm"
  1. phpstorm 配置,在设置中配置一个来自 docker 的 cli 解释器,需要设置一下容器 web 路径到本地源码路径到映射

    配置后会自动检测容器内的 xdebug

  2. 然后进行调试即可


nodejs

参考:https://juejin.cn/s/debug%20node%20js%20docker%20container

  1. 在 Dockerfile 中使用 CMD ["node", "--inspect-brk", "app.js"] 命令,以启用 Node.js 的调试模式,并在代码中插入 debugger 语句,以便在启动容器时自动停在调试器中断点处。

  2. 使用 docker exec 命令连接到正在运行的容器,并使用 Node.js 调试器手动附加到正在运行的 Node.js 进程,例如:docker exec -it <container-id> node --inspect-brk=0.0.0.0:9229 app.js,然后在 Chrome DevTools 中打开 chrome://inspect 页面,并连接到正在运行的调试器。

  3. 使用 docker-compose 配置文件启动容器,并在其中设置 portscommand,以便在容器启动时自动启用 Node.js 调试器和调试模式,例如:

    version: '3'
    services:
      app:
        build: .
        ports:
          - "9229:9229"
        command: ["node", "--inspect-brk=0.0.0.0:9229", "app.js"]

python

参考:https://tttang.com/archive/1900/

Docker配置

方法一:vscode自动识别web框架

正常编写Docker文件即可,无需增加调试相关命令

方法二:通用远程调试

需要额外增加命令

  • Dockerfile:RUN pip install debugpy
  • docker-compose.yml:(ports之后)entrypoint: [ "python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "--wait-for-client", "-m", "flask", "run", "-h", "0.0.0.0"],其中5678是vscode远程调试的端口

vscode调试配置

  • vscode 左侧调试栏->点击新建调试文件/或c+s+p->Debug: Start Debugging

  • 选择添加配置

    image-20230802164507648.png

    image-20230802163154148.png

  • 主要以Django和flask框架为例(未加nodejs等),见0x131和0x132

方法一:vscode自动识别web框架

  • 选择python->Docker: Python - Django/flask
  • 会在工程目录下生成.vscode 目录,其中包含两个json文件:
  • launch.json
{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387

    "configurations": [
        {
            "name": "Docker: Python - Django",
            "type": "docker",
            "request": "launch",
            "preLaunchTask": "docker-run: debug",
            "python": {
                "pathMappings": [
                    {
                        "localRoot": "${workspaceFolder}/web",
                        "remoteRoot": "/usr/src"
                    }
            ],
                "projectType": "django"
            }
        }
    ]
} 
  • tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "docker-build",
            "label": "docker-build",
            "platform": "python",
            "dockerBuild": {//自动生成,与docker文件保持一致
                "tag": "", 
                "dockerfile": "${workspaceFolder}/Dockerfile",
                "context": "${workspaceFolder}/[..]",
                "pull": true
            }
        },
        {
            "type": "docker-run",
            "label": "docker-run: debug",
            "dependsOn":[
                "docker-build"
            ],
            "python": {
                "args": [
                    "runserver",
                    "0.0.0.0:8000"
                ],
                "file": "web/app.py" //程序主入口,需根据实际情况修改
            }
        }
    ]

}

注意:
- 这种情况vscode可能会修改Dockerfile,如果拿不准建议提前备份一下Docker配置
- 搭建github上的工程进行调试时,由于工程文件含requirements.txt,venv pip后实际调试失败,总报错:找不到依赖库

方法二:通用远程调试

  • 选择python->Python: 远程附加->输入调试端口,默认为5678
  • 会在工程目录下生成.vscode 目录,其中包含1个json文件:
  • lanch.json
{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: 远程附加",
            "type": "python",
            "request": "attach",
            "connect": {
                "host": "localhost",
                "port": 5678 //远程调试端口
            },
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "."
                }
            ],
            "justMyCode": true
        }
    ]
}
  • docker-compose.yml的ports添加一行:- "5678:5678"

vscode调试

  • 在待调试文件代码处下断点

  • 运行docker:docker-compose.yml右键->Compose Up(第一次)或Compose Restart->等待docker正常启动

  • 开始调试:

  • 方法一:运行和调试->自动有Python: Remote Attach按钮,点击

  • 方法二:无Python: Remote Attach时,让待调试文件处于活跃状态(即当前看见的代码是调试代码)->运行和调试->齿轮右侧省略号->开始调试

    image-20230802182404531.png


java

参考: https://blog.csdn.net/haduwi/article/details/126296308

先在本地对应jar包的文件夹下启动idea,把jar包添加为库

接下来编辑运行配置

image-20240729230813110

指定端口,命令行实参选择对应版本,然后复制这行实参到我们的docker启动执行命令中(我这里是docker-entrypoint.sh)

把运行指令改为

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:6666 -jar /app/app.jar

/app/app.jar是我这里容器内的jar包路径

然后改docker-compose.yml,多设置一个端口

version: '3'
services:
  web:
    build: ../
    environment:
      # 仅为测试用flag
      FLAG: "flag{a63b4d37-7681-4850-b6a7-0d7109febb19}"
    ports:
      # 设置了暴露端口
      - 85:8080
      - 6666:6666
    restart: unless-stopped

接下来docker-compose up启动docker

IDEA这里还要在模块里把 BOOT-INF 添加到项目库依赖

image-20240729231436768

然后就可以调试了