├── dbConfig.properties ├── kubernetes ├── 00_namespace.yml ├── 01_database.yml └── 02_hellogopher.yml ├── go.mod ├── go.sum ├── dockerfile ├── readme.MD ├── main.go └── mysql.go /dbConfig.properties: -------------------------------------------------------------------------------- 1 | DATABASE_USERNAME=root 2 | DATABASE_NAME=test -------------------------------------------------------------------------------- /kubernetes/00_namespace.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: hellogopher -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module programmingpercy.tech/kubedemo 2 | 3 | go 1.18 4 | 5 | require github.com/go-sql-driver/mysql v1.6.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 2 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 3 | -------------------------------------------------------------------------------- /dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine as builder 2 | 3 | WORKDIR /app 4 | COPY . . 5 | 6 | RUN CGO_ENBALED=0 GOOS=linux GOARCH=amd64 go build -o hellogopher -ldflags="-w -s" 7 | 8 | ENTRYPOINT [ "./hellogopher" ] -------------------------------------------------------------------------------- /readme.MD: -------------------------------------------------------------------------------- 1 | # Kubernetes - The Easy Way 2 | This is a example on how to use Kubernetes. 3 | 4 | This repository is related to my tutorials where we talk through the creation of each object. 5 | 6 | Video - [Youtube]() 7 | Blog - [Medium](https://medium.com/@programmingpercy/learn-kubernetes-the-easy-way-d1cfa460c013) -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | 12 | started := time.Now() 13 | 14 | if err := connectDatabase(); err != nil { 15 | log.Fatal(err) 16 | } 17 | defer databaseConn.Close() 18 | 19 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 20 | 21 | duration := time.Now().Sub(started) 22 | 23 | if duration.Seconds() > 1000 { 24 | log.Println("Timeout triggered") 25 | w.WriteHeader(http.StatusInternalServerError) 26 | w.Write([]byte(`Im timed out`)) 27 | } else { 28 | w.WriteHeader(http.StatusOK) 29 | w.Write([]byte(`Hello gopher`)) 30 | } 31 | }) 32 | 33 | http.HandleFunc("/aligator", func(w http.ResponseWriter, r *http.Request) { 34 | fmt.Fprintf(w, "Hello Mr Aligator") 35 | }) 36 | 37 | log.Fatal(http.ListenAndServe(":8080", nil)) 38 | } 39 | -------------------------------------------------------------------------------- /kubernetes/01_database.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: mysql 5 | namespace: hellogopher 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: mysql 10 | strategy: 11 | type: Recreate 12 | template: 13 | metadata: 14 | labels: 15 | app: mysql 16 | spec: 17 | containers: 18 | - image: mysql:5.6 19 | name: mysql 20 | env: 21 | - name: MYSQL_ROOT_PASSWORD 22 | value: password 23 | ports: 24 | - containerPort: 3306 25 | name: mysql 26 | --- 27 | apiVersion: v1 28 | kind: Service 29 | metadata: 30 | name: mysql 31 | namespace: hellogopher 32 | spec: 33 | ports: 34 | - port: 3306 35 | selector: 36 | app: mysql 37 | --- 38 | apiVersion: v1 39 | kind: ConfigMap 40 | metadata: 41 | name: database-configs 42 | namespace: hellogopher 43 | data: 44 | DATABASE_USERNAME: root 45 | DATABASE_NAME: test 46 | --- 47 | apiVersion: v1 48 | kind: Secret 49 | metadata: 50 | name: database-secrets 51 | namespace: hellogopher 52 | type: Opaque 53 | data: 54 | DATABASE_PASSWORD: cGFzc3dvcmQ= 55 | -------------------------------------------------------------------------------- /kubernetes/02_hellogopher.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hellogopher 5 | namespace: hellogopher 6 | spec: # WHat state you desire for this object 7 | selector: 8 | matchLabels: 9 | app: hellogopher 10 | replicas: 1 11 | template: # When Kubernetes creates new pods, Follow this template state 12 | metadata: 13 | labels: 14 | app: hellogopher 15 | spec: 16 | containers: 17 | - name: hellogopher 18 | image: programmingpercy/hellogopher:5.0 # Dont use latest tag, 19 | imagePullPolicy: IfNotPresent 20 | ports: 21 | - containerPort: 8080 22 | resources: 23 | requests: 24 | memory: "1Mi" 25 | cpu: "50m" 26 | limits: 27 | memory: "10Mi" 28 | cpu: "100m" 29 | envFrom: 30 | - configMapRef: 31 | name: database-configs 32 | env: 33 | - name: DATABASE_PASSWORD 34 | valueFrom: 35 | secretKeyRef: 36 | name: database-secrets 37 | key: DATABASE_PASSWORD 38 | readinessProbe: 39 | initialDelaySeconds: 5 40 | timeoutSeconds: 1 41 | httpGet: 42 | path: / 43 | port: 8080 44 | livenessProbe: 45 | initialDelaySeconds: 5 46 | timeoutSeconds: 1 47 | failureThreshold: 3 48 | httpGet: 49 | path: / 50 | port: 8080 -------------------------------------------------------------------------------- /mysql.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "errors" 7 | "fmt" 8 | "log" 9 | "os" 10 | "time" 11 | 12 | _ "github.com/go-sql-driver/mysql" 13 | ) 14 | 15 | type DatabaseConfig struct { 16 | username string 17 | password string 18 | hostname string 19 | port string 20 | dbName string 21 | } 22 | 23 | var ( 24 | databaseConn *sql.DB 25 | ) 26 | 27 | func connectDatabase() error { 28 | log.Println("Trying to connect to DB") 29 | db, err := sql.Open("mysql", createDSN(true)) 30 | if err != nil { 31 | return fmt.Errorf("failed to open mysql connection: %w", err) 32 | } 33 | 34 | databaseConn = db 35 | 36 | if err := createDatabase(os.Getenv("DATABASE_NAME")); err != nil { 37 | return err 38 | } 39 | 40 | if err := db.Ping(); err != nil { 41 | return fmt.Errorf("failed to ping db: %w", err) 42 | } 43 | 44 | db, err = sql.Open("mysql", createDSN(false)) 45 | if err != nil { 46 | return fmt.Errorf("failed to open mysql connection using databasename: %w", err) 47 | } 48 | 49 | log.Println("connected to database") 50 | databaseConn = db 51 | 52 | return nil 53 | 54 | } 55 | 56 | func createDatabase(dbname string) error { 57 | log.Println("Creating database") 58 | 59 | ctx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Second) 60 | defer cancelFunc() 61 | 62 | tx, err := databaseConn.BeginTx(ctx, nil) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | res, err := tx.ExecContext(ctx, fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", dbname)) 68 | if err != nil { 69 | return err 70 | } 71 | 72 | no, err := res.RowsAffected() 73 | if err != nil { 74 | return err 75 | } 76 | 77 | if no == 0 { 78 | return errors.New("failed to create database, no rows affected") 79 | } 80 | 81 | if err := tx.Commit(); err != nil { 82 | return fmt.Errorf("failed to commmit tx: %w", err) 83 | } 84 | return nil 85 | 86 | } 87 | 88 | func createDSN(skipDB bool) string { 89 | dbCfg := getDatabaseConfig() 90 | if skipDB { 91 | return fmt.Sprintf("%s:%s@tcp(%s)/%s", dbCfg.username, dbCfg.password, dbCfg.hostname, "") 92 | } 93 | return fmt.Sprintf("%s:%s@tcp(%s)/%s", dbCfg.username, dbCfg.password, dbCfg.hostname, dbCfg.dbName) 94 | } 95 | 96 | func getDatabaseConfig() DatabaseConfig { 97 | return DatabaseConfig{ 98 | username: os.Getenv("DATABASE_USERNAME"), 99 | password: os.Getenv("DATABASE_PASSWORD"), 100 | dbName: os.Getenv("DATABASE_NAME"), 101 | hostname: os.Getenv("MYSQL_SERVICE_HOST"), 102 | port: os.Getenv("MYSQL_SERVICE_port"), 103 | } 104 | } 105 | --------------------------------------------------------------------------------