diff --git a/cmd/memtierd/Dockerfile b/cmd/memtierd/Dockerfile new file mode 100644 index 000000000..2ce0e223b --- /dev/null +++ b/cmd/memtierd/Dockerfile @@ -0,0 +1,32 @@ +FROM debian:stable-slim + +RUN apt-get update && apt-get install -y software-properties-common build-essential gnupg make curl sudo git socat vim procps + +# Install Go 1.19 +RUN curl -LO https://golang.org/dl/go1.19.linux-amd64.tar.gz && \ + tar -C /usr/local -xzf go1.19.linux-amd64.tar.gz && \ + rm go1.19.linux-amd64.tar.gz + +ENV PATH=$PATH:/usr/local/go/bin +ENV GOPATH=/go +ENV PATH=$GOPATH/bin:$PATH + +COPY . . + +# Get the Memtierd binary +RUN git clone https://github.com/intel/memtierd.git \ + && cd memtierd/ \ + && make bin/memtierd \ + && mv bin/memtierd /bin \ + && cd .. + +RUN GO111MODULE=on go get -u github.com/containerd/nri/pkg/stub +RUN GO111MODULE=on go get -u github.com/sirupsen/logrus +RUN GO111MODULE=on go get -u gopkg.in/yaml.v2 + +# Build the plugin binary +RUN go build -gcflags "all=-N -l" + +RUN mv memtierd-nri /bin/10-memtierd-nri + +CMD ["10-memtierd-nri"] diff --git a/cmd/memtierd/go.mod b/cmd/memtierd/go.mod new file mode 100644 index 000000000..727b21779 --- /dev/null +++ b/cmd/memtierd/go.mod @@ -0,0 +1,23 @@ +module memtierd-nri + +go 1.19 + +require ( + github.com/containerd/nri v0.3.1-0.20230601014931-040229d0100f + github.com/sirupsen/logrus v1.9.0 + gopkg.in/yaml.v2 v2.4.0 +) + +require ( + github.com/containerd/ttrpc v1.1.1-0.20220420014843-944ef4a40df3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/opencontainers/runtime-spec v1.1.0-rc.1 // indirect + golang.org/x/net v0.6.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + k8s.io/cri-api v0.26.1 // indirect +) diff --git a/cmd/memtierd/go.sum b/cmd/memtierd/go.sum new file mode 100644 index 000000000..1ea34cd2c --- /dev/null +++ b/cmd/memtierd/go.sum @@ -0,0 +1,129 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/containerd/nri v0.3.1-0.20230601014931-040229d0100f h1:YccqdIvYsUyuvrp+qfyJGL2Lz6XH1AGmEMc0oWi/f9E= +github.com/containerd/nri v0.3.1-0.20230601014931-040229d0100f/go.mod h1:Zw9q2lP16sdg0zYybemZ9yTDy8g7fPCIB3KXOGlggXI= +github.com/containerd/ttrpc v1.1.1-0.20220420014843-944ef4a40df3 h1:BhCp66ofL8oYcdelc3CBXc2/Pfvvgx+s+mrp9TvNgn8= +github.com/containerd/ttrpc v1.1.1-0.20220420014843-944ef4a40df3/go.mod h1:YYyNVhZrTMiaf51Vj6WhAJqJw+vl/nzABhj8pWrzle4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/onsi/ginkgo/v2 v2.5.0 h1:TRtrvv2vdQqzkwrQ1ke6vtXf7IK34RBUJafIy1wMwls= +github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg= +github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc h1:ijGwO+0vL2hJt5gaygqP2j6PfflOBrRot0IczKbmtio= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/cri-api v0.26.1 h1:HTlvEzrhrjuXvjrrGWC2UMfM3vpxxtFJSs20QffHtMA= +k8s.io/cri-api v0.26.1/go.mod h1:I5TGOn/ziMzqIcUvsYZzVE8xDAB1JBkvcwvR0yDreuw= diff --git a/cmd/memtierd/main.go b/cmd/memtierd/main.go new file mode 100644 index 000000000..771fe28ce --- /dev/null +++ b/cmd/memtierd/main.go @@ -0,0 +1,331 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "bufio" + "context" + "flag" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "syscall" + + "gopkg.in/yaml.v2" + + "github.com/sirupsen/logrus" + + "github.com/containerd/nri/pkg/api" + "github.com/containerd/nri/pkg/stub" +) + +type plugin struct { + stub stub.Stub + mask stub.EventMask +} + +type MemtierdConfig struct { + Policy Policy `yaml:"policy"` + Routines []Routines `yaml:"routines"` +} + +type Routines struct { + Name string `yaml:"name"` + Config string `yaml:"config"` +} + +type Policy struct { + Name string `yaml:"name"` + Config string `yaml:"config"` +} + +var ( + log *logrus.Logger +) + +func (p *plugin) Configure(ctx context.Context, config, runtime, version string) (stub.EventMask, error) { + log.Infof("Connected to %s/%s...", runtime, version) + + if config == "" { + return 0, nil + } + + return 0, nil +} + +func (p *plugin) StartContainer(ctx context.Context, pod *api.PodSandbox, ctr *api.Container) error { + log.Infof("Starting container %s/%s/%s...", pod.GetNamespace(), pod.GetName(), ctr.GetName()) + + podName := pod.GetName() + containerName := ctr.GetName() + annotations := pod.GetAnnotations() + + // If memtierd annotation is not present, don't execute further + class, ok := annotations["class.memtierd.nri"] + if !ok { + return nil + } + + // Check that class is of correct form + pattern := "^[A-Za-z0-9_-]+$" + regex, err := regexp.Compile(pattern) + if err != nil { + // Handle error if the pattern is invalid + log.Fatalf("Invalid regex pattern:", err) + return nil + } + + if !regex.MatchString(class) { + log.Fatalf("Invalid memtierd.class.nri!") + return nil + } + + // You can specify the template here based on the given class ex. class.memtierd.nri: low-prio -> template = low-prio.yaml + // Plugin looks in the /template directory and looks for the low-prio.yaml then + template := "" + + if class == "example-configuration" { + template = "example-configuration.yaml" + } + + fullCgroupPath := getFullCgroupPath(ctr) + podDirectory, outputFilePath, configFilePath := editMemtierdConfig(fullCgroupPath, podName, containerName, template) + startMemtierd(podName, containerName, podDirectory, outputFilePath, configFilePath) + + return nil +} + +func (p *plugin) StopContainer(ctx context.Context, pod *api.PodSandbox, ctr *api.Container) ([]*api.ContainerUpdate, error) { + log.Infof("Stopped container %s/%s/%s...", pod.GetNamespace(), pod.GetName(), ctr.GetName()) + + // + // This is the container (post-)stop request handler. You can update any + // of the remaining running containers. Take a look at the functions in + // pkg/api/update.go to see the available controls. + // + + podName := pod.GetName() + dirPath := fmt.Sprintf("/tmp/memtierd/%s", podName) + + // Kill the memtierd process + out, err := exec.Command("sudo", "pkill", "-f", dirPath).CombinedOutput() + if err != nil { + exitErr, ok := err.(*exec.ExitError) + if !ok || exitErr.ExitCode() != 1 { + // Error occurred that is not related to "no processes found" + log.Fatalf("Error killing memtierd process: %v. Output: %s\n", err, out) + } else { + // "No processes found" error, do nothing + log.Printf("No processes found for memtierd process\n") + } + } + + err = os.RemoveAll(dirPath) + if err != nil { + fmt.Println(err) + } + + return []*api.ContainerUpdate{}, nil +} + +func (p *plugin) onClose() { + log.Infof("Connection to the runtime lost, exiting...") + os.Exit(0) +} + +func getFullCgroupPath(ctr *api.Container) string { + cgroupPath := ctr.Linux.CgroupsPath + + split := strings.Split(cgroupPath, ":") + + partOne := split[0] + partTwo := fmt.Sprintf("%s-%s.scope", split[1], split[2]) + + partialPath := fmt.Sprintf("%s/%s", partOne, partTwo) + + fullPath := fmt.Sprintf("*/kubepods*/%s", partialPath) + + file, err := os.Open("/proc/mounts") + if err != nil { + log.Fatalf("failed to open /proc/mounts: %v", err) + } + defer file.Close() + + cgroupMountPoint := "" + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + fields := strings.Fields(line) + + if fields[0] == "cgroup2" { + cgroupMountPoint = fields[1] + break + } + } + if err := scanner.Err(); err != nil { + log.Fatalf("failed to read /proc/mounts: %v", err) + } + + // Find the cgroup path corresponding to the container + var fullCgroupPath string + err = filepath.WalkDir(cgroupMountPoint, func(path string, info os.DirEntry, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + matches, err := filepath.Glob(filepath.Join(path, fullPath)) + if err != nil { + return err + } + + if len(matches) > 0 { + fullCgroupPath = matches[0] + return filepath.SkipDir + } + } + + return nil + }) + + if err != nil { + log.Fatalf("failed to traverse cgroup directories: %v", err) + } + + if fullCgroupPath == "" { + log.Fatalf("cgroup path not found") + } + + log.Printf("Cgroup path: %s", fullCgroupPath) + + return fullCgroupPath +} + +func editMemtierdConfig(fullCgroupPath string, podName string, containerName string, template string) (string, string, string) { + templatePath := fmt.Sprintf("/templates/%s", template) + yamlFile, err := ioutil.ReadFile(templatePath) + if err != nil { + log.Fatalf("Error reading YAML file: %v\n", err) + } + + // Create pod directory if it doesn't exist + podDirectory := fmt.Sprintf("/tmp/memtierd/%s", podName) + if err := os.MkdirAll("/host"+podDirectory, 0755); err != nil { + log.Fatalf("Error creating directory: %v", err) + } + + outputFilePath := fmt.Sprintf("%s/memtierd.%s.output", podDirectory, containerName) + + var memtierdConfig MemtierdConfig + err = yaml.Unmarshal(yamlFile, &memtierdConfig) + if err != nil { + log.Fatalf("Error unmarshaling YAML: %v\n", err) + } + + //fullCgroupPathString := string(fullCgroupPath) + fullCgroupPathString := fullCgroupPath + + // Edit the Policy and Routine configs + policyConfigFieldString := string(memtierdConfig.Policy.Config) + policyConfigFieldString = strings.Replace(policyConfigFieldString, "$CGROUP2_ABS_PATH", fullCgroupPathString, 1) + + // Loop through the routines + for i := 0; i < len(memtierdConfig.Routines); i++ { + routineConfigFieldString := string(memtierdConfig.Routines[i].Config) + routineConfigFieldString = strings.Replace(routineConfigFieldString, "$MEMTIERD_SWAP_STATS_PATH", outputFilePath, 1) + memtierdConfig.Routines[i].Config = routineConfigFieldString + } + + memtierdConfig.Policy.Config = policyConfigFieldString + + out, err := yaml.Marshal(&memtierdConfig) + if err != nil { + log.Fatalf("Error marshaling YAML: %v\n", err) + } + + configFilePath := fmt.Sprintf("/host"+podDirectory+"/%s.yaml", containerName) + err = ioutil.WriteFile(configFilePath, out, 0644) + if err != nil { + log.Fatalf("Error writing YAML file: %v\n", err) + } + log.Infof("YAML file successfully modified.") + + return podDirectory, outputFilePath, configFilePath +} + +func startMemtierd(podName string, containerName string, podDirectory string, outputFilePath string, configFilePath string) { + log.Infof("Starting Memtierd") + + outputFile, err := os.OpenFile("/host"+outputFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + fmt.Printf("Failed to open output file: %v\n", err) + } + + // Create the command and write its output to the output file + cmd := exec.Command("memtierd", "-c", "", "-config", configFilePath) + cmd.Stdout = outputFile + cmd.Stderr = outputFile + + // Start the command in a new session and process group + cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} + + // Start the command in the background + if err := cmd.Start(); err != nil { + fmt.Printf("Failed to start command: %v\n", err) + } +} + +func main() { + var ( + pluginName string + pluginIdx string + err error + ) + + log = logrus.StandardLogger() + log.SetFormatter(&logrus.TextFormatter{ + PadLevelText: true, + }) + + flag.StringVar(&pluginName, "name", "", "plugin name to register to NRI") + flag.StringVar(&pluginIdx, "idx", "", "plugin index to register to NRI") + flag.Parse() + + p := &plugin{} + opts := []stub.Option{ + stub.WithOnClose(p.onClose), + } + if pluginName != "" { + opts = append(opts, stub.WithPluginName(pluginName)) + } + if pluginIdx != "" { + opts = append(opts, stub.WithPluginIdx(pluginIdx)) + } + + if p.stub, err = stub.New(p, opts...); err != nil { + log.Fatalf("failed to create plugin stub: %v", err) + } + + if err = p.stub.Run(context.Background()); err != nil { + log.Errorf("plugin exited (%v)", err) + os.Exit(1) + } +} diff --git a/cmd/memtierd/templates/example-configuration.yaml b/cmd/memtierd/templates/example-configuration.yaml new file mode 100644 index 000000000..c6697a15f --- /dev/null +++ b/cmd/memtierd/templates/example-configuration.yaml @@ -0,0 +1,60 @@ +# This memtierd configuration demonstrates how to configure +# memtierd-based swapping. +# +# Example: compress memory that has been idle for 10 seconds. +# +# Solution: +# +# 1. Enable compressed in-memory swap: +# +# modprobe zram +# echo 4G > /sys/block/zram0/disksize +# mkswap /dev/zram0 +# swapon /dev/zram0 +# +# 2. Start swapping all memory of processes in - $CGROUP2_ABS_PATH <- The NRI plugin finds the actual path and replaces this variable with the path. +# if pages have been idle for more than 10 seconds: +# +# memtierd -config memtierd-age-swapidle.yaml + +policy: + name: age + config: | + # The policy reads tracker counters and acts based on them in + # IntervalMs (milliseconds) periods. + intervalms: 10000 + + # The policy manages processes that can be found under listed + # cgroups paths. + pidwatcher: + name: cgroups + config: | + cgroups: + - $CGROUP2_ABS_PATH + + # If the tracker has not seen activity on a page region during last + # swapoutms, the region will be swapped out. + swapoutms: 10000 + + # The policy uses the idlepage tracker to make sure that it will + # not swap out memory that is used. The softdirty tracker cannot + # detect page reads, and the damon tracker may not detect activity + # of small address ranges due to sampling. + tracker: + name: idlepage + config: | + # Track memory in 2 MB chunks (512 pages). + pagesinregion: 512 + # If a single page has been accessed, skip the rest of the chunk. + # No need to count further: the chunk is active. + maxcountperregion: 1 + # No need to scan more often than the policy acts. + scanintervalms: 10000 + + # Low-level page mover and swapper configuration. + mover: + # IntervalMs is the period (in milliseconds) how often next + # chunk of memory is moved or swapped. + intervalms: 20 + # Bandwidth is memory swap out speed (in MB/s) + bandwidth: 100 diff --git a/cmd/memtierd/templates/example-deployment.yaml b/cmd/memtierd/templates/example-deployment.yaml new file mode 100644 index 000000000..cecd1c7cf --- /dev/null +++ b/cmd/memtierd/templates/example-deployment.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Pod +metadata: + name: example-pod + labels: + app: example-pod + annotations: + class.memtierd.nri: "example-configuration" +spec: + containers: + - name: example-pod-1 + image: + imagePullPolicy: Always + securityContext: + privileged: true + volumeMounts: + - name: host-volume + mountPath: /host + - name: host-bitmap + mountPath: /sys/kernel/mm/page_idle/bitmap + volumes: + - name: host-volume + hostPath: + path: / + - name: host-bitmap + hostPath: + path: /sys/kernel/mm/page_idle/bitmap diff --git a/cmd/memtierd/templates/pod-memtierd.yaml b/cmd/memtierd/templates/pod-memtierd.yaml new file mode 100644 index 000000000..b6fca0fdc --- /dev/null +++ b/cmd/memtierd/templates/pod-memtierd.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: Pod +metadata: + name: pod-memtierd + labels: + app: pod-memtierd +spec: + hostPID: true + containers: + - name: pod-memtierd + image: /memtierd-nri + imagePullPolicy: Always + securityContext: + privileged: true + volumeMounts: + - name: nri-socket + mountPath: /var/run/nri/nri.sock + - name: host-volume + mountPath: /host + - name: host-bitmap + mountPath: /sys/kernel/mm/page_idle/bitmap + - name: memtierd-data + mountPath: /tmp/memtierd + volumes: + - name: nri-socket + hostPath: + path: /var/run/nri/nri.sock + - name: host-volume + hostPath: + path: / + - name: host-bitmap + hostPath: + path: /sys/kernel/mm/page_idle/bitmap + - name: memtierd-data + hostPath: + path: /tmp/memtierd diff --git a/docs/index.rst b/docs/index.rst index 4fcefd194..fe237501a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,6 +8,7 @@ Welcome to NRI Plugins documentation :caption: Contents: resource-policy/index.rst + memtierd/index.rst contributing.md diff --git a/docs/memtierd/README.md b/docs/memtierd/README.md new file mode 100644 index 000000000..b4c643dc5 --- /dev/null +++ b/docs/memtierd/README.md @@ -0,0 +1,72 @@ +# Memtierd NRI plugin + +An easy way to start using [Memtierd](https://github.com/intel/memtierd/tree/main) as a memory manager in your Kubernetes cluster. + +## Prerequisities +- NRI enabled on your container runtime + +## Making your own image + +```console +# Build the image +docker build cmd/memtierd/ -t memtierd-nri + +# Then tag and push the image to your registry +docker tag memtierd-nri +docker push +``` + +See [running Memtierd NRI plugin in a pod](#running-memtierd-nri-plugin-in-a-pod) on how to deploy it. + +## Running a self compiled version locally + +To compile your own version run: +```console +go build . +``` + +Then move the output to the plugin path specified in your /etc/containerd/config.toml file: +```toml +plugin_path = "/opt/nri/plugins" +``` + +You also need to specify an index for the plugin in the plugin name. The index is like an priority for the plugin to be executed in case you have multiple plugins. + +For example: +```console +mv memtier-nri /opt/nri/plugins/10-memtier-nri +``` + +Then just run: +```console +/opt/nri/plugin/10-memtier-nri +``` + +After that you should see something like the following: +```console +INFO [0000] Created plugin 10-memtier-nri (10-memtier-nri, handles RunPodSandbox,StopPodSandbox,RemovePodSandbox,CreateContainer,PostCreateContainer,StartContainer,PostStartContainer,UpdateContainer,PostUpdateContainer,StopContainer,RemoveContainer) +INFO [0000] Registering plugin 10-memtier-nri... +... +``` + +Now the plugin is ready to recognize events happening in the cluster. + +## Running Memtierd NRI plugin in a pod + +To run Memtierd NRI plugin in a pod change the image in cmd/memtierd/templates/pod-memtierd.yaml to point at your image and then deploy the pod to your cluster: + +```console +kubectl apply -f cmd/memtierd/templates/pod-memtierd.yaml +``` + +## Using Memtierd with your deployments + +Workload configurations are defined with the "class.memtierd.nri" annotation. Now for example the following annotation: + +```yaml +class.memtierd.nri: "high-prio-configuration" +``` + +Would start Memtierd for the workload with the configuration found in "cmd/memtierd/templates/high-prio-configuration.yaml" + +Workloads need to run in privileged state. diff --git a/docs/memtierd/creating-your-own-memtierd-configurations.md b/docs/memtierd/creating-your-own-memtierd-configurations.md new file mode 100644 index 000000000..1af09c122 --- /dev/null +++ b/docs/memtierd/creating-your-own-memtierd-configurations.md @@ -0,0 +1,16 @@ +# Creating your own configurations for Memtierd + +When deploying pods that you want to be tracked by Memtierd, you need to specify a configuration that is used to tell Memtierd how to track your pod. This can be done by adding your own configurations to the cmd/memtierd/templates/ directory before building the image for your Memtierd NRI plugin. + +## How to create a configuration + +Many sample configurations are specified [here](https://github.com/intel/memtierd/tree/main/sample-configs) with comments on what each parameter does. + +- Take a configuration from the sample configs, add your own parameters based on your workloads needs and then add that configuration to the templates/ directory. +- When specifying your deployments add the "class.memtierd.nri" annotation to point to the configuration file you want to use. See the templates/example-deployment.yaml for example. + +## Allowing the use of new configurations + +Just adding the configuration to the templates is not enough. You will also need to modify the StartContainer() function in cmd/memtierd/main.go to make the plugin look for the correct template you just added. There is an example in the code on how to do this easily. + +After these steps just make a new Memtierd NRI plugin image and you can use your newly created configuration with your workloads. diff --git a/docs/memtierd/index.rst b/docs/memtierd/index.rst new file mode 100644 index 000000000..8eb1b4df9 --- /dev/null +++ b/docs/memtierd/index.rst @@ -0,0 +1,8 @@ +Memtierd Plugin +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + creating-your-own-memtierd-configurations.md