17/04/2020 - DOCKER, GO, MYSQL
İki servis/konteyneriniz olduğunu varsayın. Biri diğerinden bağlantı kabul etmeye hazır olmalıdır. Fark ettiğiniz gibi, "biri çalışıyor olmalı" demedim çünkü "bağlantıları kabul etmeye hazır" ile "çalışıyor olma" arasında fark var. Docker compose öğesinin depends_on
anahtarı sorunu her zaman çözemez çünkü yalnızca konteynerin çalışıp çalışmadığını kontrol eder. Eğer bir servis MySQL, RabbitMQ, Elasticsearch benzeri servislere bağlıysa, genellikle böyle olur. Bunların bağlantıları kabul etmeleri zaman alır. Bu sorunu çözmek için ek bir komut dosyası kullanabiliriz. Bu komut dosyası, ana hizmeti çalıştırmadan önce bağlantıları kabul etmeye hazır olana kadar bu hizmetleri düzenli olarak pingleyecektir.
Bu örnekte bir Go ve MySQL servisimiz var. Go MySQL'e bağlıdır. MySQL bağlantıları kabul etmede yavaştır. Komut dosyamızı, Go servisini başlatmadan önce MySQL'in bağlantıları kabul etmesini beklemeye zorlamak için kullanacağız. MySQL hazır olduğunu söyledikten sonra Go servisini başlatacağız.
.
├── cmd
│ └── app
│ └── main.go
├── docker
│ └── dev
│ ├── docker-compose.yaml
│ └── go
│ ├── Dockerfile
│ └── init.sh
├── go.mod
└── go.sum
package main
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
log.Println("Staring the app ...")
db, err := sql.Open("mysql", "user:pass@tcp(app-db:3306)/db")
if err != nil {
log.Fatalln(err)
}
defer db.Close()
if err := db.Ping(); err != nil {
log.Fatalln(err)
}
log.Println("Connected to the db ...")
select {}
}
#
# STAGE 1: prepare
#
FROM golang:1.13.1-alpine3.10 as prepare
WORKDIR /source
COPY go.mod .
COPY go.sum .
RUN go mod download
#
# STAGE 2: build
#
FROM prepare AS build
COPY . .
RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o bin/app -v cmd/app/main.go
#
# STAGE 3: run
#
FROM alpine:3.10 as run
COPY --from=build /source/bin/app /app
COPY --from=build /source/docker/dev/go/init.sh /init.sh
RUN chmod +x /init.sh
ENTRYPOINT ["/init.sh"]
Aynı komut dosyasını diğer hizmetler için de kullanabilir veya buraya başka hizmetler ekleyebilirsiniz.
#!/bin/sh
set -eu
echo "Checking DB connection ..."
i=0
until [ $i -ge 10 ]
do
nc -z app-db 3306 && break
i=$(( i + 1 ))
echo "$i: Waiting for DB 1 second ..."
sleep 1
done
if [ $i -eq 10 ]
then
echo "DB connection refused, terminating ..."
exit 1
fi
echo "DB is up ..."
/app
version: "3.4"
services:
app-go:
build:
context: "../.."
dockerfile: "docker/dev/go/Dockerfile"
ports:
- "8001:8000"
app-db:
image: "mysql:5.7.24"
ports:
- "3001:3306"
environment:
MYSQL_ROOT_PASSWORD: "root"
MYSQL_DATABASE: "db"
Aslında burada sonlandırmayı simüle etmek için 1
saniyesini kod içinde 0.001
(1 ms) olarak değiştirdim.
Recreating dev_app-go_1 ... done
Starting dev_app-db_1 ... done
Attaching to dev_app-db_1, dev_app-go_1
app-db_1 | 2020-04-17T19:31:26.156962Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated.
app-db_1 | 2020-04-17T19:31:26.158227Z 0 [Note] mysqld (mysqld 5.7.24) starting as process 1 ...
app-db_1 | 2020-04-17T19:31:26.161203Z 0 [Note] InnoDB: PUNCH HOLE support available
app-db_1 | 2020-04-17T19:31:26.161454Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
app-go_1 | Checking DB connection ...
app-go_1 | 1: Waiting for DB 1 second ...
app-db_1 | 2020-04-17T19:31:26.161563Z 0 [Note] InnoDB: Uses event mutexes
app-go_1 | 2: Waiting for DB 1 second ...
app-go_1 | 3: Waiting for DB 1 second ...
app-db_1 | 2020-04-17T19:31:26.161853Z 0 [Note] InnoDB: GCC builtin __atomic_thread_fence() is used
app-go_1 | 4: Waiting for DB 1 second ...
app-db_1 | 2020-04-17T19:31:26.162130Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
app-db_1 | 2020-04-17T19:31:26.162368Z 0 [Note] InnoDB: Using Linux native AIO
app-go_1 | 5: Waiting for DB 1 second ...
app-go_1 | 6: Waiting for DB 1 second ...
app-go_1 | 7: Waiting for DB 1 second ...
app-db_1 | 2020-04-17T19:31:26.162986Z 0 [Note] InnoDB: Number of pools: 1
app-go_1 | 8: Waiting for DB 1 second ...
app-db_1 | 2020-04-17T19:31:26.163323Z 0 [Note] InnoDB: Using CPU crc32 instructions
app-go_1 | 9: Waiting for DB 1 second ...
app-db_1 | 2020-04-17T19:31:26.164968Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M
app-db_1 | 2020-04-17T19:31:26.172335Z 0 [Note] InnoDB: Completed initialization of buffer pool
app-go_1 | 10: Waiting for DB 1 second ...
app-go_1 | DB connection refused, terminating ...
dev_app-go_1 exited with code 1
Recreating dev_app-go_1 ... done
Starting dev_app-db_1 ... done
Attaching to dev_app-db_1, dev_app-go_1
app-db_1 | 2020-04-17T19:31:26.156962Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated.
app-db_1 | 2020-04-17T19:31:26.158227Z 0 [Note] mysqld (mysqld 5.7.24) starting as process 1 ...
app-db_1 | 2020-04-17T19:31:26.161203Z 0 [Note] InnoDB: PUNCH HOLE support available
app-db_1 | 2020-04-17T19:31:26.161454Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
app-go_1 | Checking DB connection ...
app-go_1 | 1: Waiting for DB 1 second ...
app-db_1 | 2020-04-17T19:31:26.161563Z 0 [Note] InnoDB: Uses event mutexes
app-go_1 | 2: Waiting for DB 1 second ...
app-go_1 | 3: Waiting for DB 1 second ...
app-db_1 | 2020-04-17T19:45:21.324028Z 0 [Note] mysqld: ready for connections.
app-db_1 | Version: '5.7.24' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
app-go_1 | DB is up ...
app-db_1 | 2020-04-17T19:45:21.663343Z 2 [Note] Got an error reading communication packets
app-go_1 | 2020/04/17 19:45:21 Staring the app ...
app-go_1 | 2020/04/17 19:45:21 Connected to the db ...