├── .gitignore ├── color_client ├── .gitignore ├── go.mod ├── Dockerfile ├── main.go └── go.sum ├── color_server ├── .gitignore ├── go.mod ├── Dockerfile ├── main.go └── go.sum ├── images └── red-blue-green.png ├── deploy-istio.sh ├── README.md └── istio └── manifest-istio.yaml.template /.gitignore: -------------------------------------------------------------------------------- 1 | debug/ 2 | _output/ -------------------------------------------------------------------------------- /color_client/.gitignore: -------------------------------------------------------------------------------- 1 | color_client 2 | -------------------------------------------------------------------------------- /color_server/.gitignore: -------------------------------------------------------------------------------- 1 | color_server 2 | -------------------------------------------------------------------------------- /images/red-blue-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tetratelabs/aws-app-mesh-to-istio-example/main/images/red-blue-green.png -------------------------------------------------------------------------------- /color_client/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aws/aws-app-mesh-examples/walkthroughs/howto-http2/color_client 2 | 3 | go 1.13 4 | 5 | require golang.org/x/net v0.7.0 6 | -------------------------------------------------------------------------------- /color_server/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aws/aws-app-mesh-examples/walkthroughs/howto-http2/color_server 2 | 3 | go 1.13 4 | 5 | require golang.org/x/net v0.7.0 6 | -------------------------------------------------------------------------------- /color_client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/amazonlinux/amazonlinux:2 AS builder 2 | RUN yum update -y && \ 3 | yum install -y ca-certificates unzip tar gzip git && \ 4 | yum clean all && \ 5 | rm -rf /var/cache/yum 6 | 7 | RUN curl -LO https://golang.org/dl/go1.17.1.linux-amd64.tar.gz && \ 8 | tar -C /usr/local -xzvf go1.17.1.linux-amd64.tar.gz 9 | 10 | ENV PATH="${PATH}:/usr/local/go/bin" 11 | ENV GOPATH="${HOME}/go" 12 | ENV PATH="${PATH}:${GOPATH}/bin" 13 | 14 | # Use the default go proxy 15 | ARG GO_PROXY=https://proxy.golang.org 16 | 17 | WORKDIR /go/src/github.com/aws/aws-app-mesh-examples/walkthroughs/howto-http2/color_client 18 | 19 | # Set the proxies for the go compiler. 20 | ENV GOPROXY=$GO_PROXY 21 | 22 | # go.mod and go.sum go into their own layers. 23 | # This ensures `go mod download` happens only when go.mod and go.sum change. 24 | COPY go.mod . 25 | COPY go.sum . 26 | RUN go mod download 27 | 28 | COPY . . 29 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /color_client . 30 | 31 | FROM public.ecr.aws/amazonlinux/amazonlinux:2 32 | RUN yum update -y && \ 33 | yum install -y ca-certificates && \ 34 | yum clean all && \ 35 | rm -rf /var/cache/yum 36 | COPY --from=builder /color_client /color_client 37 | 38 | ENTRYPOINT ["/color_client"] 39 | -------------------------------------------------------------------------------- /color_server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/amazonlinux/amazonlinux:2 AS builder 2 | RUN yum update -y && \ 3 | yum install -y ca-certificates unzip tar gzip git && \ 4 | yum clean all && \ 5 | rm -rf /var/cache/yum 6 | 7 | RUN curl -LO https://golang.org/dl/go1.17.1.linux-amd64.tar.gz && \ 8 | tar -C /usr/local -xzvf go1.17.1.linux-amd64.tar.gz 9 | 10 | ENV PATH="${PATH}:/usr/local/go/bin" 11 | ENV GOPATH="${HOME}/go" 12 | ENV PATH="${PATH}:${GOPATH}/bin" 13 | 14 | # Use the default go proxy 15 | ARG GO_PROXY=https://proxy.golang.org 16 | 17 | WORKDIR /go/src/github.com/aws/aws-app-mesh-examples/walkthroughs/howto-http2/color_server 18 | 19 | # Set the proxies for the go compiler. 20 | ENV GOPROXY=$GO_PROXY 21 | 22 | # go.mod and go.sum go into their own layers. 23 | # This ensures `go mod download` happens only when go.mod and go.sum change. 24 | COPY go.mod . 25 | COPY go.sum . 26 | RUN go mod download 27 | 28 | COPY . . 29 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /color_server . 30 | 31 | FROM public.ecr.aws/amazonlinux/amazonlinux:2 32 | RUN yum update -y && \ 33 | yum install -y ca-certificates && \ 34 | yum clean all && \ 35 | rm -rf /var/cache/yum 36 | COPY --from=builder /color_server /color_server 37 | 38 | ENTRYPOINT ["/color_server"] 39 | -------------------------------------------------------------------------------- /color_client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "net" 9 | "net/http" 10 | "os" 11 | 12 | "golang.org/x/net/http2" 13 | ) 14 | 15 | func main() { 16 | color_host := os.Getenv("COLOR_HOST") 17 | if color_host == "" { 18 | log.Fatalf("no COLOR_HOST defined") 19 | } 20 | port := os.Getenv("PORT") 21 | if port == "" { 22 | log.Fatalf("no PORT defined") 23 | } 24 | log.Printf("COLOR_HOST is: %v", color_host) 25 | log.Printf("PORT is: %v", port) 26 | // Create an h2c client 27 | client := &http.Client{ 28 | Transport: &http2.Transport{ 29 | // Allow non-https urls 30 | AllowHTTP: true, 31 | // Make the transport *not-actually* use TLS 32 | DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { 33 | return net.Dial(network, addr) 34 | }, 35 | }, 36 | } 37 | http.HandleFunc("/ping", func(w http.ResponseWriter, req *http.Request) {}) 38 | 39 | http.HandleFunc("/color", func(w http.ResponseWriter, req *http.Request) { 40 | resp, err := client.Get("http://" + color_host) 41 | if err != nil { 42 | http.Error(w, err.Error(), 500) 43 | log.Printf("Could not get color: %v", err) 44 | return 45 | } 46 | defer resp.Body.Close() 47 | color, err := ioutil.ReadAll(resp.Body) 48 | if err != nil { 49 | http.Error(w, err.Error(), 400) 50 | log.Printf("Could not read response body: %v", err) 51 | return 52 | } 53 | log.Printf("Got color response: %s", string(color)) 54 | fmt.Fprint(w, string(color)) 55 | }) 56 | 57 | http.HandleFunc("/setFlake", func(w http.ResponseWriter, req *http.Request) { 58 | resp, err := client.Get("http://" + color_host + req.URL.RequestURI()) 59 | if err != nil { 60 | http.Error(w, err.Error(), 500) 61 | log.Printf("Could not set flakiness: %v", err) 62 | return 63 | } 64 | defer resp.Body.Close() 65 | body, err := ioutil.ReadAll(resp.Body) 66 | if err != nil { 67 | http.Error(w, err.Error(), 400) 68 | log.Printf("Could not read response body: %v", err) 69 | return 70 | } 71 | log.Printf("Got setFlake response: %s", string(body)) 72 | if resp.StatusCode != 200 { 73 | http.Error(w, string(body), resp.StatusCode) 74 | return 75 | } 76 | fmt.Fprint(w, string(body)) 77 | }) 78 | log.Fatal(http.ListenAndServe("0.0.0.0:"+port, nil)) 79 | } 80 | -------------------------------------------------------------------------------- /color_server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math/rand" 7 | "net/http" 8 | "os" 9 | "strconv" 10 | 11 | "golang.org/x/net/http2" 12 | "golang.org/x/net/http2/h2c" 13 | ) 14 | 15 | // This is a simple HTTP server that supports cleartext HTTP1.1 and HTTP2 16 | // requests as well as upgrading to HTTP2 via h2c 17 | // Example: 18 | // $ COLOR=red PORT=8080 go run main.go 19 | // $ curl --http2-prior-knowledge -i localhost:8080 20 | func main() { 21 | color := os.Getenv("COLOR") 22 | if color == "" { 23 | log.Fatalf("no COLOR defined") 24 | } 25 | port := os.Getenv("PORT") 26 | if port == "" { 27 | log.Fatalf("no PORT defined") 28 | } 29 | log.Printf("COLOR is: %v", color) 30 | log.Printf("PORT is: %v", port) 31 | flakeRate := float32(0.0) 32 | flakeCode := 200 33 | 34 | mux := http.NewServeMux() 35 | mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {}) 36 | 37 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 38 | log.Printf("Received request: %v", r) 39 | if rand.Float32() < flakeRate { 40 | http.Error(w, "flaky server", flakeCode) 41 | return 42 | } 43 | fmt.Fprintf(w, "%s", color) 44 | }) 45 | 46 | mux.HandleFunc("/setFlake", func(w http.ResponseWriter, r *http.Request) { 47 | log.Printf("Received request: %v", r) 48 | query := r.URL.Query() 49 | rates, ok := query["rate"] 50 | if !ok { 51 | http.Error(w, "rate must be specified", 400) 52 | log.Printf("Could not read rate parameter") 53 | return 54 | } 55 | rate, err := strconv.ParseFloat(rates[0], 32) 56 | if err != nil { 57 | http.Error(w, err.Error(), 400) 58 | log.Printf("Could not parse rate parameter: %v", err) 59 | return 60 | } 61 | if rate < 0.0 || rate > 1.0 { 62 | http.Error(w, "rate must be between 0.0 and 1.0", 400) 63 | log.Printf("Invalid rate parameter: %v", rate) 64 | return 65 | } 66 | 67 | codes, ok := query["code"] 68 | if !ok { 69 | http.Error(w, "code must be specified", 400) 70 | log.Printf("Could not read code parameter: %v", err) 71 | return 72 | } 73 | 74 | code, err := strconv.ParseInt(codes[0], 10, 32) 75 | if err != nil { 76 | http.Error(w, err.Error(), 400) 77 | log.Printf("Could not parse code parameter: %v", err) 78 | return 79 | } 80 | 81 | fmt.Fprintf(w, "rate: %g, code: %d", flakeRate, flakeCode) 82 | flakeRate = float32(rate) 83 | flakeCode = int(code) 84 | }) 85 | h2s := &http2.Server{} 86 | h1s := &http.Server{ 87 | Addr: "0.0.0.0:" + port, 88 | Handler: h2c.NewHandler(mux, h2s), 89 | } 90 | log.Fatal(h1s.ListenAndServe()) 91 | } 92 | -------------------------------------------------------------------------------- /deploy-istio.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | if [ -z $AWS_ACCOUNT_ID ]; then 6 | echo "AWS_ACCOUNT_ID environment variable is not set." 7 | exit 1 8 | fi 9 | 10 | if [ -z $AWS_DEFAULT_REGION ]; then 11 | echo "AWS_DEFAULT_REGION environment variable is not set." 12 | exit 1 13 | fi 14 | 15 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" 16 | PROJECT_NAME="howto-k8s-http2" 17 | APP_NAMESPACE=${PROJECT_NAME} 18 | APP_ISTIO_NAMESPACE=${APP_NAMESPACE}-istio 19 | ECR_URL="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com" 20 | ECR_IMAGE_PREFIX="${ECR_URL}/${PROJECT_NAME}" 21 | CLIENT_APP_IMAGE="${ECR_IMAGE_PREFIX}/color_client" 22 | COLOR_APP_IMAGE="${ECR_IMAGE_PREFIX}/color_server" 23 | AWS_CLI_VERSION=$(aws --version 2>&1 | cut -d/ -f2 | cut -d. -f1) 24 | 25 | error() { 26 | echo $1 27 | exit 1 28 | } 29 | 30 | 31 | check_istio_k8s() { 32 | numberIstiodReplicas=$(kubectl get deployment -n istio-system istiod -o json | jq -r .status.readyReplicas) 33 | if [ $numberIstiodReplicas -gt 0 ]; then 34 | echo "istiod check passed! $nuberIstiodReplicas running" 35 | else 36 | error "$PROJECT_NAME requires istio to be deployed first. See https://tetratelabs.github.io/tid-addon-workshop/4_deploy_tid_addon/" 37 | fi 38 | } 39 | 40 | ecr_login() { 41 | if [ $AWS_CLI_VERSION -gt 1 ]; then 42 | aws ecr get-login-password --region ${AWS_DEFAULT_REGION} --profile $AWS_PROFILE | \ 43 | docker login --username AWS --password-stdin ${ECR_URL} 44 | else 45 | $(aws ecr get-login --no-include-email --profile $AWS_PROFILE) 46 | fi 47 | } 48 | 49 | deploy_images() { 50 | ecr_login 51 | for app in color_client color_server; do 52 | aws ecr describe-repositories --repository-name $PROJECT_NAME/$app --profile $AWS_PROFILE >/dev/null 2>&1 || aws ecr create-repository --profile $AWS_PROFILE --repository-name $PROJECT_NAME/$app >/dev/null 53 | docker build -t ${ECR_IMAGE_PREFIX}/${app} ${DIR}/${app} --build-arg GO_PROXY=${GO_PROXY:-"https://proxy.golang.org"} 54 | docker push ${ECR_IMAGE_PREFIX}/${app} 55 | done 56 | } 57 | 58 | deploy_app() { 59 | EXAMPLES_OUT_DIR="${DIR}/_output/" 60 | mkdir -p ${EXAMPLES_OUT_DIR} 61 | eval "cat <${EXAMPLES_OUT_DIR}/manifest-istio.yaml 65 | 66 | kubectl apply -f ${EXAMPLES_OUT_DIR}/manifest-istio.yaml 67 | } 68 | 69 | main() { 70 | check_istio_k8s 71 | 72 | if [ -z $SKIP_IMAGES ]; then 73 | echo "deploy images..." 74 | deploy_images 75 | fi 76 | 77 | deploy_app 78 | } 79 | 80 | main 81 | -------------------------------------------------------------------------------- /color_client/go.sum: -------------------------------------------------------------------------------- 1 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 2 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 3 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 4 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 5 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 6 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 7 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 8 | golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= 9 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 10 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 11 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 12 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 13 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 14 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 15 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 16 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 17 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 18 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 19 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 20 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 21 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 22 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 23 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 24 | golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= 25 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 26 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 27 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 28 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 29 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 30 | -------------------------------------------------------------------------------- /color_server/go.sum: -------------------------------------------------------------------------------- 1 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 2 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 3 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 4 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 5 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 6 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 7 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 8 | golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= 9 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 10 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 11 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 12 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 13 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 14 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 15 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 16 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 17 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 18 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 19 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 20 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 21 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 22 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 23 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 24 | golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= 25 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 26 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 27 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 28 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 29 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This repository is based on the example from AWS Repo that covers [base setup](https://github.com/aws/aws-app-mesh-examples/blob/main/walkthroughs/eks/base.md). The example 4 | here deploys the same the simple `color` application and provides the same expected result. For the traffic steering we use Istio ([Tetrate's distro](https://aws.amazon.com/marketplace/pp/prodview-rm6w3vwyibt46?sr=0-1&ref_=beagle&applicationId=AWSMPContessa)) while the upstream example leverages AWS App Mesh. This example allows App Mesh users to get the technical 5 | guidance on migrating from AWS App Mesh to Istio. The Istio example can be run side-by-side in the same cluster with applications that use AWS App Mesh. Kubernetes `namespace` is a natural separator between the applications that leverage AWS App Mesh and Istio in the single cluster. 6 | 7 | 8 | ## Prerequisites 9 | 10 | 1. Deploy Istio - any way to deploy Istio will work. The easiest one is probably via [Tetrate Istio Distro add-on](https://tetratelabs.github.io/tid-addon-workshop/4_deploy_tid_addon/). 11 | 12 | 2. Install Docker. It is needed to build the demo application images. 13 | 14 | 3. Make sure that kubectl and jq are deployed on your console. 15 | 16 | 4. Your kubernetes context is pointing to the correct cluster. 17 | 18 | 19 | ## Setup 20 | 21 | 1. Clone this repository and navigate to the root directory., all commands will be ran from this location 22 | 1. **Your** account id: 23 | 24 | ``` 25 | export AWS_ACCOUNT_ID= 26 | ``` 27 | 28 | 1. **Region** e.g. us-west-2 29 | 30 | ``` 31 | export AWS_DEFAULT_REGION=us-west-2 32 | ``` 33 | 34 | 1. **Image Synchronization** (optional) 35 | 36 | to save time if the images are already synchronized, setup the following flag: 37 | 38 | ```bash 39 | export SKIP_IMAGES=true 40 | ``` 41 | 42 | 1. Deploy by running the script that is heavily modified version of the AWS App Mesh script 43 | 44 | ```. 45 | ./deploy-istio.sh 46 | ``` 47 | 48 | 1. Note that the example apps use go modules. If you have trouble accessing https://proxy.golang.org during the deployment you can override the GOPROXY by setting `GO_PROXY=direct` 49 | 50 | ``` 51 | GO_PROXY=direct ./deploy.sh 52 | ``` 53 | 54 | 1. Set up [port forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to route requests from your local computer to the **client** pod. The local port is up to you but we will assume the local port is **7000** for this walkthrough. Below is an example that retrieves namespace that is set by the `deploy-istio.sh` script. 55 | 56 | ```bash 57 | APP_ISTIO_NAMESPACE=$(kubectl get namespaces -ojson | jq -r .items[].metadata.name | grep "\-istio") 58 | kubectl -n $APP_ISTIO_NAMESPACE port-forward deployment/client 7000:8080 > /dev/null & 59 | ``` 60 | 61 | 1. In order to validate that the requests are distributed between your internal services equally run the requests against `client` pod. It will forward the requests to `color` service and those requests will be equally distributed between `red`, `green` and `blue` services by Istio **ROUND_ROBIN** algorithm: 62 | : 63 | ``` 64 | END=3 65 | for i in $(seq 1 $END); do curl -s localhost:7000/color; echo; done 66 | ``` 67 | 68 | 1. Using the name of the client pod run the following command to tail the client app logs: 69 | ``` 70 | kubectl logs -f -n app 71 | ``` 72 | 73 | 1. Initially the state of your mesh is a client node with an even distribution to 3 color services (red, blue, and green) over HTTP/2. Prove this by running the following command a few times: 74 | ``` 75 | curl localhost:7000/color 76 | ``` 77 | 78 | The output should look similar to below: 79 | 80 | ![Expected output](images/red-blue-green.png "Expected output") 81 | 82 | ## Conclusion 83 | 84 | This example helps to understand a general changes that allow to replace AWS App Mesh functionality with Istio powered Service Mesh. Please provide us your App Mesh use-case via GH Issues. 85 | This would allow Tetrate to share more examples on App Mesh migration to Istio Service Mesh. -------------------------------------------------------------------------------- /istio/manifest-istio.yaml.template: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: ${APP_ISTIO_NAMESPACE} 6 | labels: 7 | istio-injection: enabled 8 | --- 9 | apiVersion: networking.istio.io/v1alpha3 10 | kind: VirtualService 11 | metadata: 12 | name: color 13 | namespace: ${APP_ISTIO_NAMESPACE} 14 | spec: 15 | hosts: 16 | - color.${APP_ISTIO_NAMESPACE}.svc.cluster.local 17 | http: 18 | - route: 19 | - destination: 20 | host: color 21 | --- 22 | apiVersion: networking.istio.io/v1alpha3 23 | kind: DestinationRule 24 | metadata: 25 | namespace: ${APP_ISTIO_NAMESPACE} 26 | name: color 27 | spec: 28 | host: color.${APP_ISTIO_NAMESPACE}.svc.cluster.local 29 | trafficPolicy: 30 | loadBalancer: 31 | simple: ROUND_ROBIN 32 | --- 33 | apiVersion: v1 34 | kind: Service 35 | metadata: 36 | name: client 37 | namespace: ${APP_ISTIO_NAMESPACE} 38 | spec: 39 | ports: 40 | - port: 8080 41 | name: http2 42 | selector: 43 | app: client 44 | --- 45 | apiVersion: apps/v1 46 | kind: Deployment 47 | metadata: 48 | name: client 49 | namespace: ${APP_ISTIO_NAMESPACE} 50 | spec: 51 | replicas: 1 52 | selector: 53 | matchLabels: 54 | app: client 55 | template: 56 | metadata: 57 | labels: 58 | app: client 59 | spec: 60 | containers: 61 | - name: app 62 | image: ${CLIENT_APP_IMAGE} 63 | ports: 64 | - containerPort: 8080 65 | env: 66 | - name: "COLOR_HOST" 67 | value: "color.${APP_ISTIO_NAMESPACE}.svc.cluster.local:8080" 68 | - name: "PORT" 69 | value: "8080" 70 | --- 71 | apiVersion: v1 72 | kind: Service 73 | metadata: 74 | name: red 75 | namespace: ${APP_ISTIO_NAMESPACE} 76 | spec: 77 | ports: 78 | - port: 8080 79 | name: http2 80 | selector: 81 | app: color 82 | version: red 83 | --- 84 | apiVersion: apps/v1 85 | kind: Deployment 86 | metadata: 87 | name: red 88 | namespace: ${APP_ISTIO_NAMESPACE} 89 | spec: 90 | replicas: 1 91 | selector: 92 | matchLabels: 93 | app: color 94 | version: red 95 | template: 96 | metadata: 97 | labels: 98 | app: color 99 | version: red 100 | spec: 101 | containers: 102 | - name: app 103 | image: ${COLOR_APP_IMAGE} 104 | ports: 105 | - containerPort: 8080 106 | env: 107 | - name: "COLOR" 108 | value: "red" 109 | - name: "PORT" 110 | value: "8080" 111 | --- 112 | apiVersion: v1 113 | kind: Service 114 | metadata: 115 | name: blue 116 | namespace: ${APP_ISTIO_NAMESPACE} 117 | spec: 118 | ports: 119 | - port: 8080 120 | name: http2 121 | selector: 122 | app: color 123 | version: blue 124 | --- 125 | apiVersion: apps/v1 126 | kind: Deployment 127 | metadata: 128 | name: blue 129 | namespace: ${APP_ISTIO_NAMESPACE} 130 | spec: 131 | replicas: 1 132 | selector: 133 | matchLabels: 134 | app: color 135 | version: blue 136 | template: 137 | metadata: 138 | labels: 139 | app: color 140 | version: blue 141 | spec: 142 | containers: 143 | - name: app 144 | image: ${COLOR_APP_IMAGE} 145 | ports: 146 | - containerPort: 8080 147 | env: 148 | - name: "COLOR" 149 | value: "blue" 150 | - name: "PORT" 151 | value: "8080" 152 | --- 153 | apiVersion: v1 154 | kind: Service 155 | metadata: 156 | name: green 157 | namespace: ${APP_ISTIO_NAMESPACE} 158 | spec: 159 | ports: 160 | - port: 8080 161 | name: http2 162 | selector: 163 | app: color 164 | version: green 165 | --- 166 | apiVersion: apps/v1 167 | kind: Deployment 168 | metadata: 169 | name: green 170 | namespace: ${APP_ISTIO_NAMESPACE} 171 | spec: 172 | replicas: 1 173 | selector: 174 | matchLabels: 175 | app: color 176 | version: green 177 | template: 178 | metadata: 179 | labels: 180 | app: color 181 | version: green 182 | spec: 183 | containers: 184 | - name: app 185 | image: ${COLOR_APP_IMAGE} 186 | ports: 187 | - containerPort: 8080 188 | env: 189 | - name: "COLOR" 190 | value: "green" 191 | - name: "PORT" 192 | value: "8080" 193 | --- 194 | apiVersion: v1 195 | kind: Service 196 | metadata: 197 | name: color 198 | namespace: ${APP_ISTIO_NAMESPACE} 199 | spec: 200 | ports: 201 | - port: 8080 202 | name: http2 203 | selector: 204 | app: color --------------------------------------------------------------------------------