diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..9299d16
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,4 @@
+.dockerignore
+docker-bake.hcl
+docker-compose.yml
+Dockerfile
diff --git a/.gitignore b/.gitignore
index 95e4256..68f8678 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,5 @@
 
 /target
 /out
+
+/docker-data
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..022a25b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,22 @@
+FROM rust:1 as builder
+
+RUN rustup target add x86_64-unknown-linux-musl && \
+    apt update && \
+    apt install -y musl-tools musl-dev && \
+    update-ca-certificates
+
+COPY ./ /emgauwa
+
+FROM builder as builder-core
+WORKDIR /emgauwa/core
+RUN cargo build --target x86_64-unknown-linux-musl --release
+
+FROM builder as builder-controller
+WORKDIR /emgauwa/controller
+RUN cargo build --target x86_64-unknown-linux-musl --release
+
+FROM scratch
+COPY --from=builder-core /emgauwa/core/target/x86_64-unknown-linux-musl/release/emgauwa-core /usr/bin/emgauwa-core
+COPY --from=builder-controller /emgauwa/controller/target/x86_64-unknown-linux-musl/release/emgauwa-controller /usr/bin/emgauwa-controller
+
+CMD ["echo", "please specify command /usr/bin/emgauwa-core or /usr/bin/emgauwa-controller"]
diff --git a/Makefile b/Makefile
index f6c0284..5bf6cf3 100644
--- a/Makefile
+++ b/Makefile
@@ -7,3 +7,16 @@ git-status:
 
 git-diff:
 	git diff --submodule=diff
+
+cargo-all:
+	cd common && cargo $(ACTION)
+	cd controller && cargo $(ACTION)
+	cd core && cargo $(ACTION)
+cargo-build:
+	$(MAKE) ACTION=build cargo-all
+cargo-update:
+	$(MAKE) ACTION=update cargo-all
+
+docker-bake:
+	cd controller && docker builder bake
+	cd core && docker builder bake
diff --git a/docker-bake.hcl b/docker-bake.hcl
new file mode 100644
index 0000000..a571888
--- /dev/null
+++ b/docker-bake.hcl
@@ -0,0 +1,15 @@
+variable "REG" {
+    default = "registry.serguzim.me"
+}
+variable "REPO" {
+    default = "emgauwa/combi"
+}
+variable "TAG" {
+    default = "latest"
+}
+
+target "default" {
+    output = ["type=docker"]
+    dockerfile = "./Dockerfile"
+    tags = ["${REG}/${REPO}:latest", "${REG}/${REPO}:${TAG}"]
+}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..5df8273
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,29 @@
+services:
+  core:
+    image: registry.serguzim.me/emgauwa/combi
+    command: /usr/bin/emgauwa-core
+    ports:
+      - "4419:4419"
+    environment:
+      EMGAUWA_CORE__SERVER__HOST: 0.0.0.0
+      EMGAUWA_CORE__DATABASE: sqlite:///data/core.sqlite
+    volumes:
+      - ./docker-data:/data
+  controller1:
+    image: registry.serguzim.me/emgauwa/combi
+    command: /usr/bin/emgauwa-controller
+    environment:
+      EMGAUWA_CONTROLLER__SERVER__HOST: core
+      EMGAUWA_CONTROLLER__DATABASE: sqlite:///data/controller1.sqlite
+    volumes:
+      - ./controller/emgauwa-controller.json:/etc/emgauwa/controller.json
+      - ./docker-data:/data
+  controller2:
+    image: registry.serguzim.me/emgauwa/combi
+    command: /usr/bin/emgauwa-controller
+    environment:
+      EMGAUWA_CONTROLLER__SERVER__HOST: core
+      EMGAUWA_CONTROLLER__DATABASE: sqlite:///data/controller2.sqlite
+    volumes:
+      - ./controller/emgauwa-controller.json:/etc/emgauwa/controller.json
+      - ./docker-data:/data