Skip to content

Commit 5c1258c

Browse files
committed
✨ (setup): add basic setup
0 parents  commit 5c1258c

File tree

12 files changed

+337
-0
lines changed

12 files changed

+337
-0
lines changed

.gitignore

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Code coverage profiles and other test artifacts
15+
*.out
16+
coverage.*
17+
*.coverprofile
18+
profile.cov
19+
20+
# Dependency directories (remove the comment below to include it)
21+
# vendor/
22+
23+
# Go workspace file
24+
go.work
25+
go.work.sum
26+
27+
# env file
28+
.env
29+
30+
# Editor/IDE
31+
# .idea/
32+
# .vscode/
33+
bin
34+
gg
35+
mage

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# golang-customize-container-runtime
2+
3+
這邊透過 golang 來建立一個可執行的 container runtime,模擬 docker run 時,docker engine 所執行的事情
4+
5+
## container 概念
6+
7+
![container-concept](container-concept.png)
8+
9+
## 實做的架構
10+
11+
![implementation-architecture](implementation-architecture.png)
12+
13+
14+
## 套用 alpine 的 rootfs
15+
16+
```shell
17+
wget https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/alpine-minirootfs-3.18.0-x86_64.tar.gz
18+
mkdir rootfs
19+
tar -xzf alpine-minirootfs-3.18.0-x86_64.tar.gz -C rootfs
20+
```
21+
22+
## golang code analyze

Taskfile.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
version: '3'
2+
3+
dotenv: ['.env']
4+
5+
tasks:
6+
default:
7+
cmds:
8+
- echo "This is task cmd"
9+
silent: true
10+
11+
build:
12+
cmds:
13+
- CGO_ENABLED=0 GOOS=linux go build -o bin/self-container cmd/main.go
14+
silent: true
15+
run:
16+
cmds:
17+
- ./bin/self-container
18+
deps:
19+
- build
20+
silent: true
21+
run_awstest:
22+
cmds:
23+
- ./bin/awstest
24+
deps:
25+
- build_awstest
26+
silent: true
27+
28+
build-mage:
29+
cmds:
30+
- CGO_ENABLED=0 GOOS=linux go build -o ./mage mage-tools/mage.go
31+
silent: true
32+
33+
build-gg:
34+
cmds:
35+
- ./mage -d mage-tools -compile ../gg
36+
deps:
37+
- build-mage
38+
silent: true
39+
40+
coverage:
41+
cmds:
42+
- go test -v -cover ./...
43+
silent: true
44+
test:
45+
cmds:
46+
- go test -v ./...
47+
silent: true
48+
49+

cmd/main.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
"syscall"
8+
9+
util "github.com/leetcode-golang-classroom/golang-customize-container-runtime/internal"
10+
)
11+
12+
// main --> docker run <container-name> cmd args
13+
// go run main.go run args
14+
func main() {
15+
// os.Args 0 1
16+
// <binary> args
17+
switch os.Args[1] {
18+
case "run":
19+
run()
20+
case "child":
21+
child()
22+
default:
23+
panic("unknown command")
24+
}
25+
}
26+
27+
// run --> fork the process to child
28+
func run() {
29+
fmt.Printf("running %v as PID %d\n", os.Args[2:], os.Getpid())
30+
// for the process to the child
31+
cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...)
32+
// let execution stdin, stdout, stderr pipeout
33+
cmd.Stdin = os.Stdin
34+
cmd.Stdout = os.Stdout
35+
cmd.Stderr = os.Stderr
36+
// setup for isolated namespace
37+
cmd.SysProcAttr = &syscall.SysProcAttr{
38+
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
39+
}
40+
// panic for any error
41+
util.Must(cmd.Run())
42+
}
43+
44+
// child --> run the dispatch cmd
45+
func child() {
46+
fmt.Printf("running %v as PID %d\n", os.Args[2:], os.Getpid())
47+
// set hostname of the new UTS namespace
48+
util.Must(syscall.Sethostname([]byte(util.AppConfig.Hostname)))
49+
cmd := exec.Command(os.Args[2], os.Args[3:]...)
50+
// let execution stdin, stdout, stderr pipeout
51+
cmd.Stdin = os.Stdin
52+
cmd.Stdout = os.Stdout
53+
cmd.Stderr = os.Stderr
54+
55+
util.Must(syscall.Chroot(util.AppConfig.RootFS))
56+
util.Must(os.Chdir("/"))
57+
util.Must(syscall.Mount("proc", "proc", "proc", 0, ""))
58+
// panic for any error
59+
util.Must(cmd.Run())
60+
}

container-concept.png

46.5 KB
Loading

go.mod

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module github.com/leetcode-golang-classroom/golang-customize-container-runtime
2+
3+
go 1.24.0
4+
5+
require (
6+
github.com/magefile/mage v1.15.0
7+
github.com/spf13/viper v1.20.1
8+
)
9+
10+
require (
11+
github.com/fsnotify/fsnotify v1.8.0 // indirect
12+
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
13+
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
14+
github.com/sagikazarmark/locafero v0.7.0 // indirect
15+
github.com/sourcegraph/conc v0.3.0 // indirect
16+
github.com/spf13/afero v1.12.0 // indirect
17+
github.com/spf13/cast v1.7.1 // indirect
18+
github.com/spf13/pflag v1.0.6 // indirect
19+
github.com/subosito/gotenv v1.6.0 // indirect
20+
go.uber.org/atomic v1.9.0 // indirect
21+
go.uber.org/multierr v1.9.0 // indirect
22+
golang.org/x/sys v0.29.0 // indirect
23+
golang.org/x/text v0.21.0 // indirect
24+
gopkg.in/yaml.v3 v3.0.1 // indirect
25+
)

go.sum

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
5+
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
6+
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
7+
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
8+
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
9+
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
10+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
11+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
12+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
13+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
14+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
15+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
16+
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
17+
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
18+
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
19+
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
20+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
21+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
22+
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
23+
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
24+
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
25+
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
26+
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
27+
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
28+
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
29+
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
30+
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
31+
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
32+
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
33+
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
34+
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
35+
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
36+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
37+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
38+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
39+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
40+
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
41+
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
42+
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
43+
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
44+
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
45+
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
46+
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
47+
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
48+
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
49+
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
50+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
51+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
52+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
53+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
54+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

implementation-architecture.png

101 KB
Loading

internal/config.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package util
2+
3+
import (
4+
"log"
5+
6+
"github.com/spf13/viper"
7+
)
8+
9+
type Config struct {
10+
RootFS string `mapstructure:"ROOTFS"` // 系統資料夾,也就是可以看到 boot 這類系統資料的資料夾
11+
Hostname string `mapstructure:"HOSTNAME"`
12+
}
13+
14+
var AppConfig *Config
15+
16+
func init() {
17+
v := viper.New()
18+
v.AddConfigPath(".")
19+
v.SetConfigName(".env")
20+
v.SetConfigType("env")
21+
v.AutomaticEnv()
22+
FailOnError(v.BindEnv("ROOTFS"), "failed to bind ROOTFS")
23+
FailOnError(v.BindEnv("HOSTNAME"), "failed to bind HOSTNAME")
24+
err := v.ReadInConfig()
25+
if err != nil {
26+
log.Println("Load from environment variable")
27+
}
28+
err = v.Unmarshal(&AppConfig)
29+
if err != nil {
30+
FailOnError(err, "Failed to read enivronment")
31+
}
32+
}
33+
34+
func FailOnError(err error, msg string) {
35+
if err != nil {
36+
log.Fatalf("%s: %s", msg, err)
37+
}
38+
}

internal/util.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package util
2+
3+
// Must - just panic error if err != nil
4+
func Must(err error) {
5+
if err != nil {
6+
panic(err)
7+
}
8+
}

0 commit comments

Comments
 (0)