我正在尝试完成以下在GKE上部署Wordpress的教程:https://cloud.google.com/kubernetes-engine/docs/tutorials/persistent-disk
我使用了terraform来配置gcp资源,而不是教程中推荐的gcp。以下是导致CrashLoopBackOff状态的部署。
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- image: wordpress
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: 127.0.0.1:3306
# These secrets are required to start the pod.
- name: WORDPRESS_DB_USER
valueFrom:
secretKeyRef:
name: cloudsql-db-credentials
key: username
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: cloudsql-db-credentials
key: password
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
# Change archtek-wordpress:us-west1:archtek-wordpress-postgres-instance here to include your GCP
# project, the region of your Cloud SQL instance and the name
# of your Cloud SQL instance. The format is
# ::
- name: cloudsql-proxy
image: gcr.io/cloudsql-docker/gce-proxy:1.11
command: ["/cloud_sql_proxy",
"-instances=archtek-wordpress:us-west1:archtek-wordpress-mysql-instance=tcp:3306",
# If running on a VPC, the Cloud SQL proxy can connect via Private IP. See:
# https://cloud.google.com/sql/docs/mysql/private-ip for more info.
# "-ip_address_types=PRIVATE",
"-credential_file=/secrets/cloudsql/key.json"]
securityContext:
runAsUser: 2 # non-root user
allowPrivilegeEscalation: false
volumeMounts:
- name: cloudsql-instance-credentials
mountPath: /secrets/cloudsql
readOnly: true
imagePullPolicy: Always
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wordpress-volumeclaim
- name: cloudsql-instance-credentials
secret:
secretName: cloudsql-instance-credentials
当我描述吊舱时,我在日志中看到以下内容:
wordpress-54c68dbf59-5djfx wordpress MySQL Connection Error: (2002) Connection refused
为了排除凭据无效的想法,我使用了用于创建cloudsql-db-credentials
的用户名和密码,即我的部署yaml中引用的k8s机密,并运行了此操作。
$: gcloud sql connect archtek-wordpress-mysql-instance -u wordpress
我可以连接,没问题。但我发现我也不能这样做:
$: mysql -u wordpress -p'$CLOUD_SQL_PASSWORD' ()
-h 35.197.7.98 -P 3306
-D archtek-wordpress:us-west1:archtek-wordpress-mysql-instance -v
返回:
ERROR 2003 (HY000): Can't connect to MySQL server on '35.197.7.98' (60)
我知道,当使用gcloud
客户端连接到cloudsql数据库时,它会在身份验证前的5分钟内将ip列入白名单,这可能解释了mysql
客户端无法进行身份验证的原因。但是,我不确定这个理由是否适用于我在集群中的部署。cloudsql是否也需要被列入白名单才能接受身份验证请求?
以下是用于配置cloudsql实例的terraform文件:
resource "google_sql_database_instance" "postgres" {
name = "archtek-wordpress-mysql-instance"
database_version = "MYSQL_5_7"
settings {
tier = "db-f1-micro"
availability_type = "ZONAL"
}
}
尝试从GKE
集群外部连接时遇到的错误:
错误2003(HY000(:无法连接到'35.197.798'(60(上的MySQL服务器
这是因为您连接的站点(IP(没有被授权这样做。使用:
$ gcloud sql connect ...
允许在5分钟内连接到SQL
实例。
在GKE
中使用CloudSQL proxy
时,您不需要授权连接的网络。
您可以在GCP -> SQL -> Instance -> Connections
中看到授权部分。
此外,您还可以查看pod(wordpress
和cloudsql-proxy
(的日志,以确定哪个pod导致了问题(而不是$ kubectl describe
(:
$ kubectl logs POD_NAME -c wordpress
关于CloudSQL
和sql-proxy
:的更多参考
-
Cloud.google.com:SQL:MySQL:诊断问题
-
Cloud.google.com:SQL:SQL代理:故障排除
假设您使用github页面中的.tf
文件为CloudSQL
实例创建了用户,那么它失败可能是有原因的。负责创建用户wordpress
的部分有错误的主机参数(以下示例经过编辑(:
resource "google_sql_user" "users" {
name = "wordpress"
instance = google_sql_database_instance.postgres.name
# host = "*" <- BAD
host = "%" # <- GOOD
password = random_password.password.result
}
我无法使用以下参数连接到服务器:host = "*"
。将其从"*"
更改为"%"
解决了我的问题。
我已经创建了.tf
文件,这些文件类似于官方GKE
指南的部分:
- Cloud.google.com:Kubernetes引擎:教程:永久磁盘
将Terraform连接到GCP
项目的指南:
- Terraform.io:谷歌:指南:入门
使用的文件:
main.tf
vpc.tf
-创建一个VPC
(基于注释中链接的github(gke.tf
-在新的VPC
中创建一个GKE
集群mysql.tf
-创建一个CloudSQL
实例和一个用户wordpress
pvc.tf
-为Wordpress
部署创建PVC
sa.tf
-创建一个ServiceAccount
,并使用访问CloudSQL
实例所需的权限进行绑定secret.tf
-为上述ServiceAccount
创建密钥,并为Wordpress
和CloudSQL
pod创建Kubernetes
机密deployment.tf
-创建一个将运行Wordpress
和cloudsql-proxy
的部署
每次添加新文件时,我都会运行以下命令(按以上顺序(:
$ terraform init
$ terraform apply
main.tf
:
provider "google" {
project = "ENTER-YOUR-PROJECT-ID"
region = "europe-west3"
zone = "europe-west3-c"
}
variable project {
type = string
default = "ENTER-YOUR-PROJECT-ID"
}
variable zone {
type = string
default = "europe-west3-c"
}
variable region {
type = string
default = "europe-west3"
}
vpc.tf
:
resource "google_compute_network" "terraform-network" {
name = "terraform-network"
auto_create_subnetworks = "false"
}
resource "google_compute_subnetwork" "terraform-subnet" {
name = "terraform-subnet"
region = var.region
network = google_compute_network.terraform-network.name
ip_cidr_range = "10.0.0.0/24"
}
gke.tf
:
resource "google_container_cluster" "gke-terraform" {
name = "gke-terraform"
location = var.zone
initial_node_count = 1
network = google_compute_network.terraform-network.name
subnetwork = google_compute_subnetwork.terraform-subnet.name
}
我还参加了
$ gcloud container clusters get-credentials gke-terraform --zone=europe-west3-c
mysql.tf
resource "google_sql_database_instance" "cloudsql" {
name = "cloudsql-terraform"
database_version = "MYSQL_5_7"
settings {
tier = "db-f1-micro"
availability_type = "ZONAL"
}
}
data "google_sql_database_instance" "cloudsql" {
name = "cloudsql-terraform"
}
resource "random_password" "wordpress-cloudsql-password" {
length = 18
special = true
override_special = "_%@"
}
resource "local_file" "password-file" {
content = random_password.wordpress-cloudsql-password.result
filename = "./password-file"
}
resource "google_sql_user" "cloudsql-wordpress-user" {
name = "wordpress"
instance = google_sql_database_instance.cloudsql.name
host = "%"
password = random_password.wordpress-cloudsql-password.result
}
pvc.tf
:
resource "google_compute_disk" "terraform-pd" {
name = "terraform-disk"
type = "pd-standard"
zone = "europe-west3-c"
}
resource "kubernetes_persistent_volume" "terraform-pv" {
metadata {
name = "wordpress-pv"
}
spec {
capacity = {
storage = "10Gi"
}
storage_class_name = "standard"
access_modes = ["ReadWriteOnce"]
persistent_volume_source {
gce_persistent_disk {
pd_name = google_compute_disk.terraform-pd.name
}
}
}
}
resource "kubernetes_persistent_volume_claim" "terraform-pvc" {
metadata {
name = "wordpress-pvc"
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "standard"
resources {
requests = {
storage = "10Gi"
}
}
volume_name = kubernetes_persistent_volume.terraform-pv.metadata.0.name
}
}
sa.tf
:
resource "google_service_account" "cloudsql-proxy-terraform" {
account_id = "cloudsql-proxy-terraform"
display_name = "cloudsql-proxy-terraform"
}
data "google_service_account" "cloudsql-proxy-terraform" {
account_id = "cloudsql-proxy-terraform"
}
resource "google_project_iam_binding" "cloudsql-proxy-binding" {
project = var.project
role = "roles/cloudsql.client"
members = [
"serviceAccount:${google_service_account.cloudsql-proxy-terraform.email}",
]
}
secret.tf
:
resource "google_service_account_key" "cloudsql-proxy-key" {
service_account_id = google_service_account.cloudsql-proxy-terraform.name
}
resource "kubernetes_secret" "cloudsql-instance-credentials-terraform" {
metadata {
name = "cloudsql-instance-credentials-terraform"
}
data = {
"key.json" = base64decode(google_service_account_key.cloudsql-proxy-key.private_key)
}
}
resource "kubernetes_secret" "cloudsql-db-credentials-terraform" {
metadata {
name = "cloudsql-db-credentials-terraform"
}
data = {
"username" = "wordpress"
"password" = random_password.wordpress-cloudsql-password.result
}
}
deployment.tf
:
resource "kubernetes_deployment" "wordpress-deployment" {
metadata {
name = "wordpress-deployment"
labels = {
app = "wordpress"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "wordpress"
}
}
template {
metadata {
labels = {
app = "wordpress"
}
}
spec {
container {
image = "wordpress"
name = "wordpress"
env {
name = "WORDPRESS_DB_HOST"
value = "127.0.0.1:3306"
}
env {
name = "WORDPRESS_DB_USER"
value_from {
secret_key_ref {
name = kubernetes_secret.cloudsql-db-credentials-terraform.metadata.0.name
key = "username"
}
}
}
env {
name = "WORDPRESS_DB_PASSWORD"
value_from {
secret_key_ref {
name = kubernetes_secret.cloudsql-db-credentials-terraform.metadata.0.name
key = "password"
}
}
}
port {
name = "http"
container_port = 80
protocol = "TCP"
}
volume_mount {
mount_path = "/var/www/html"
name = "wordpress-persistent-storage"
}
}
container {
image = "gcr.io/cloudsql-docker/gce-proxy:1.11"
name = "cloudsql-proxy"
command = ["/cloud_sql_proxy",
"-instances=${google_sql_database_instance.cloudsql.connection_name}=tcp:3306",
"-credential_file=/secrets/cloudsql/key.json"]
security_context {
run_as_user = 2
allow_privilege_escalation = "false"
}
volume_mount {
mount_path = "/secrets/cloudsql"
name = "cloudsql-instance-credentials-terraform"
read_only = "true"
}
}
volume {
name = "wordpress-persistent-storage"
persistent_volume_claim {
claim_name = "wordpress-pvc"
}
}
volume {
name = "cloudsql-instance-credentials-terraform"
secret {
secret_name = "cloudsql-instance-credentials-terraform"
}
}
}
}
}
}
在检查资源创建是否正确($ kubectl logs POD_NAME -c CONTAINER_NAME
(后,您可以使用公开您的Wordpress
$ kubectl expose deployment wordpress-deployment --type=LoadBalancer --port=80