mirror of https://github.com/ory/kratos
feat: in docker debug support with delve (#1789)
This commit is contained in:
parent
aac05d146c
commit
37325a18d9
|
|
@ -0,0 +1,18 @@
|
|||
FROM golang:1.16-buster
|
||||
ENV CGO_ENABLED 1
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends inotify-tools psmisc
|
||||
RUN go get github.com/go-delve/delve/cmd/dlv
|
||||
|
||||
COPY script/debug-entrypoint.sh /entrypoint.sh
|
||||
|
||||
VOLUME /dockerdev
|
||||
|
||||
WORKDIR /dockerdev
|
||||
|
||||
ENV DELVE_PORT 40000
|
||||
ENV SERVICE_NAME service
|
||||
|
||||
EXPOSE 8000 $DELVE_PORT
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
version: '3.7'
|
||||
|
||||
services:
|
||||
${SERVICE_NAME}:
|
||||
build:
|
||||
dockerfile: ./.docker/Dockerfile-debug
|
||||
ports:
|
||||
- ${REMOTE_DEBUGGING_PORT}:40000
|
||||
security_opt:
|
||||
- apparmor=unconfined
|
||||
cap_add:
|
||||
- SYS_PTRACE
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ${SERVICE_ROOT}
|
||||
target: /dockerdev
|
||||
read_only: false
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
---
|
||||
id: debug-docker-delve-ory-kratos
|
||||
title: Debugging Ory Kratos in Docker with Delve
|
||||
---
|
||||
|
||||
Very often, there is a need to debug Kratos being deployed as a Docker image. To
|
||||
support this, Kratos ships with a couple of files:
|
||||
|
||||
- The `Dockerfile-debug` file, which you can find in the `.docker` directory.
|
||||
- The `docker-compose.template.dbg` file, which you can find in the same
|
||||
directory. This file defines a template for a service, one would like to debug
|
||||
in Docker
|
||||
- and a supplementary `debug-entrypoint.sh` skript, located in the `script`
|
||||
directory.
|
||||
|
||||
Actually, these files do not include any Kratos specifica and thus can be used
|
||||
for any Golang based project. As you already could infer, this support is meant
|
||||
to be used in a docker-compose setup as described below. You can however run it
|
||||
as a standalone Docker container as well. You can find some information on how
|
||||
to achieve this at the end of this document.
|
||||
|
||||
## As part of a docker-compose setup
|
||||
|
||||
Imagine you have the following project structure:
|
||||
|
||||
- docker-compose - a directory containing your `docker-compose.yaml` file
|
||||
- kratos - a directory containing the Kratos code
|
||||
- kratos-frontend - a directory containing a frontend application for Kratos
|
||||
|
||||
The `docker-compose.yml` mentioned above could look as follows:
|
||||
|
||||
```yaml
|
||||
version: '3.7'
|
||||
|
||||
volumes:
|
||||
postgres-db:
|
||||
|
||||
services:
|
||||
postgresd:
|
||||
image: postgres:9.6
|
||||
ports:
|
||||
- '5432:5432'
|
||||
volumes:
|
||||
- type: volume
|
||||
source: postgres-db
|
||||
target: /var/lib/postgresql/data
|
||||
read_only: false
|
||||
environment:
|
||||
- PGDATA=/var/lib/postgresql/data/pgdata
|
||||
- POSTGRES_PASSWORD=secret
|
||||
- POSTGRES_USER=kratos
|
||||
|
||||
kratos-migrate:
|
||||
image: kratos
|
||||
build:
|
||||
context: ../kratos
|
||||
dockerfile: ./.docker/Dockerfile-build
|
||||
environment:
|
||||
- DSN=postgres://kratos:secret@postgresd:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4
|
||||
volumes:
|
||||
- type: bind
|
||||
source: path-to-kratos-config
|
||||
target: /etc/config/kratos
|
||||
command: migrate sql -e --yes
|
||||
depends_on:
|
||||
- postgresd
|
||||
|
||||
kratos:
|
||||
image: kratos
|
||||
build:
|
||||
context: ../kratos
|
||||
dockerfile: ./.docker/Dockerfile-build
|
||||
depends_on:
|
||||
- kratos-migrate
|
||||
ports:
|
||||
- '4433:4433' # public
|
||||
- '4434:4434' # admin
|
||||
command: serve -c /etc/config/kratos/kratos.yml --watch-courier --dev
|
||||
volumes:
|
||||
- type: bind
|
||||
source: path-to-kratos-config
|
||||
target: /etc/config/kratos
|
||||
|
||||
kratos-frontend:
|
||||
image: kratos-frontend
|
||||
build:
|
||||
context: ../kratos-kratos-frontend
|
||||
dockerfile: ./Dockerfile
|
||||
env_file:
|
||||
- file-containing-all-required-configuration.env
|
||||
```
|
||||
|
||||
To enable debugging of Kratos without changing the above docker-compose file,
|
||||
you can do the following (from the docker-compose directory):
|
||||
|
||||
```bash
|
||||
SERVICE_NAME=kratos SERVICE_ROOT=../kratos REMOTE_DEBUGGING_PORT=9999 envsubst < ../kratos/.docker/docker-compose.template.dbg \
|
||||
> docker-compose.kratos.tmp
|
||||
docker-compose -f docker-compose.yaml -f docker-compose.kratos.tmp up --build -d kratos
|
||||
```
|
||||
|
||||
The first line will create an overwrite docker-compose file to have a debug
|
||||
configuration for the kratos service. The second line will start a debug
|
||||
container by
|
||||
|
||||
- mounting your `kratos` directory into the resulting Docker container,
|
||||
- downloading Delve,
|
||||
- building Kratos inside the container,
|
||||
- starting it in Delve with the arguments, you've defined in your regular
|
||||
docker-compose file - in the example above, this would be
|
||||
`serve -c /etc/config/kratos/kratos.yml --watch-courier --dev` - and
|
||||
- watching for changes on any go file within the mounted code base.
|
||||
|
||||
Each time you change a .go file, the Delve process will be stopped, Kratos will
|
||||
be recompiled and Delve will be started again. With other words, you'll have to
|
||||
re-connect with your debugger again after each change.
|
||||
|
||||
As you can see from the above usage, the `docker-compose.template.dbg` template
|
||||
expects the following variables to be defined:
|
||||
|
||||
- `SERVICE_ROOT` - the root directory of the service to be started in the debug
|
||||
mode.
|
||||
- `SERVICE_NAME` - the name of the service from the docker-compose file.
|
||||
- `REMOTE_DEBUGGING_PORT` - the host port, the Delve listening port should be
|
||||
exposed as. This is the port you should connect your remote debugger to.
|
||||
|
||||
If you run docker-compose this way, the container run with debugging enabled
|
||||
will wait until the debugger connects. If your IDE supports remote debugging,
|
||||
set host to `localhost` and port to the value, you've used for
|
||||
`REMOTE_DEBUGGING_PORT` in your remote debugging configuration.
|
||||
|
||||
## As a standalone Docker container
|
||||
|
||||
If you just would like to start Kratos in a container in debug mode, you can
|
||||
just use the `Dockerfile-debug` file instead of the regular `Dockerfile`. Make
|
||||
however sure your build context in the root directory of Kratos and not the
|
||||
`.docker` directory. In your IDE the debug configuration has to reference that
|
||||
file. In addition, you'll have to expose the Delve service port 40000 under the
|
||||
port 8000, as well as the actual port of the service, you'll like to access from
|
||||
your host, configure the bind mounts and set the run options to
|
||||
`--security-opt="apparmor=unconfined" --cap-add=SYS_PTRACE`.
|
||||
|
|
@ -108,7 +108,8 @@
|
|||
{
|
||||
"Debug & Help": [
|
||||
"debug/csrf",
|
||||
"debug/performance-out-of-memory-password-hashing-argon2"
|
||||
"debug/performance-out-of-memory-password-hashing-argon2",
|
||||
"debug/debugging_in_docker"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
#!/bin/bash
|
||||
|
||||
FILE_CHANGE_LOG_FILE=/tmp/changes.log
|
||||
SERVICE_ARGS="$@"
|
||||
|
||||
log() {
|
||||
echo "***** $1 *****"
|
||||
}
|
||||
|
||||
init() {
|
||||
log "Initializing"
|
||||
truncate -s 0 ${FILE_CHANGE_LOG_FILE}
|
||||
tail -f ${FILE_CHANGE_LOG_FILE} &
|
||||
}
|
||||
|
||||
build() {
|
||||
log "Building ${SERVICE_NAME} binary"
|
||||
go env -w GOPROXY="proxy.golang.org,direct"
|
||||
go mod download
|
||||
go build -gcflags "all=-N -l" -o /${SERVICE_NAME}
|
||||
}
|
||||
|
||||
start() {
|
||||
log "Starting Delve"
|
||||
dlv --listen=:${DELVE_PORT} --headless=true --api-version=2 --accept-multiclient exec /${SERVICE_NAME} -- ${SERVICE_ARGS} &
|
||||
}
|
||||
|
||||
restart() {
|
||||
build
|
||||
|
||||
log "Killing old processes"
|
||||
killall dlv
|
||||
killall ${SERVICE_NAME}
|
||||
|
||||
start
|
||||
}
|
||||
|
||||
watch() {
|
||||
log "Watching for changes"
|
||||
inotifywait -e "MODIFY,DELETE,MOVED_TO,MOVED_FROM" -m -r ${PWD} | (
|
||||
while true; do
|
||||
read path action file
|
||||
ext=${file: -3}
|
||||
if [[ "$ext" == ".go" ]]; then
|
||||
echo "$file"
|
||||
fi
|
||||
done
|
||||
) | (
|
||||
WAITING=""
|
||||
while true; do
|
||||
file=""
|
||||
read -t 1 file
|
||||
if test -z "$file"; then
|
||||
if test ! -z "$WAITING"; then
|
||||
echo "CHANGED"
|
||||
WAITING=""
|
||||
fi
|
||||
else
|
||||
log "File ${file} changed" >> ${FILE_CHANGE_LOG_FILE}
|
||||
WAITING=1
|
||||
fi
|
||||
done
|
||||
) | (
|
||||
while true; do
|
||||
read TMP
|
||||
restart
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
# main part
|
||||
init
|
||||
build
|
||||
start
|
||||
watch
|
||||
Loading…
Reference in New Issue