{"id":19748701,"url":"https://github.com/doitintl/cloudrun-cloudsql-psc","last_synced_at":"2026-03-03T07:36:29.508Z","repository":{"id":219348426,"uuid":"748828852","full_name":"doitintl/cloudrun-cloudsql-psc","owner":"doitintl","description":"Accessing CloudSQL with Private Service Connect enabled from Cloud Run","archived":false,"fork":false,"pushed_at":"2024-01-29T16:17:56.000Z","size":22,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-16T13:30:21.766Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/doitintl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-01-26T20:37:06.000Z","updated_at":"2024-01-26T22:05:07.000Z","dependencies_parsed_at":"2024-01-29T18:13:47.164Z","dependency_job_id":"9b4d9c93-ef46-43c7-8c3d-4a1979f7a0da","html_url":"https://github.com/doitintl/cloudrun-cloudsql-psc","commit_stats":null,"previous_names":["doitintl/cloudrun-cloudsql-psc"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doitintl%2Fcloudrun-cloudsql-psc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doitintl%2Fcloudrun-cloudsql-psc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doitintl%2Fcloudrun-cloudsql-psc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doitintl%2Fcloudrun-cloudsql-psc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/doitintl","download_url":"https://codeload.github.com/doitintl/cloudrun-cloudsql-psc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240252191,"owners_count":19772059,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T02:23:05.619Z","updated_at":"2026-03-03T07:36:24.451Z","avatar_url":"https://github.com/doitintl.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Accessing CloudSQL with Private Service Connect from Cloud Run\n\nThis approach ensures that your database connections remain private and isolated, reducing the risk of unauthorized access and meeting stringent regulatory requirements. It also offers improved performance, lower latency, and cost savings, while giving you greater control over network access policies. By leveraging Private Service Connect, you can build robust and reliable systems that prioritize data privacy and network efficiency, making it an essential practice in modern cloud development.\n\n## Environment Variables\n\nAssuming your using Cloud Shell or a terminal on your PC with Google Cloud SDK installed\n\n`export PROJECT_ID=$(gcloud config get-value project)`\n\n`export PROJECT_USER=$(gcloud config get-value core/account)`\n\n`export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format=\"value(projectNumber)\")`\n\n`export IDNS=${PROJECT_ID}.svc.id.goog`\n\n`export GCP_REGION=\"us-central1\" `\n\n`export GCP_ZONE=\"us-central1-a\"`\n\n`export NETWORK_NAME=\"default\"`\n\n`export SQL_NETWORK_NAME=\"cloudsql\"`\n\n`export SUBNET_NAME=\"sql-psc\"`\n\n`export DB_INSTANCE_NAME=\"instance01\"`\n\n`export DB_INSTANCE_VERSION=\"MYSQL_8_0\"`\n\n`export CONNECTOR=run2csql`\n\n\n\n## APIs\n\nEnabled the APIs for your project\n```bash\n  gcloud services enable compute.googleapis.com \\\n    storage.googleapis.com \\\n    sqladmin.googleapis.com \\\n    dns.googleapis.com\n```\n    \n## Create VPC for CloudSQL MySQL\n\nCreate a network\n\n```bash\n  gcloud compute networks create $SQL_NETWORK_NAME --subnet-mode=auto\n```\n\nDefault firewall rules\n\n```bash\ngcloud compute firewall-rules create ${SQL_NETWORK_NAME}-allow-internal \\\n    --action=ALLOW \\\n    --direction=INGRESS \\\n    --network=${SQL_NETWORK_NAME} \\\n    --priority=1000 \\\n    --rules=tcp:0-65535,udp:0-65535,icmp \\\n    --source-ranges=10.128.0.0/9\n```\n\n```bash\ngcloud compute firewall-rules create ${SQL_NETWORK_NAME}-allow-ssh \\\n    --action=ALLOW \\\n    --direction=INGRESS \\\n    --network=${SQL_NETWORK_NAME} \\\n    --priority=1000 \\\n    --rules=tcp:22 \\\n    --source-ranges=0.0.0.0/0\n```\n\n```bash\ngcloud compute firewall-rules create ${SQL_NETWORK_NAME}-allow-icmp \\\n    --action=ALLOW \\\n    --direction=INGRESS \\\n    --network=${SQL_NETWORK_NAME} \\\n    --priority=1000 \\\n    --rules=icmp \\\n    --source-ranges=0.0.0.0/0\n```\n\n```bash\ngcloud compute firewall-rules create ${SQL_NETWORK_NAME}-allow-db \\\n    --action=ALLOW \\\n    --direction=INGRESS \\\n    --network=${SQL_NETWORK_NAME} \\\n    --priority=1000 \\\n    --rules=tcp:5432 \\\n    --source-ranges=10.10.0.0/24\n```\n\nAdd a subnet\n```bash\ngcloud compute networks subnets create $SUBNET_NAME \\\n    --network=$SQL_NETWORK_NAME \\\n    --range=10.10.0.0/24 \\\n    --region=$GCP_REGION\n```\n## Creating CloudSQL MySQL\n\n```bash\ngcloud sql instances create $DB_INSTANCE_NAME \\\n    --project=$PROJECT_ID \\\n    --region=$GCP_REGION \\\n    --enable-private-service-connect \\\n    --allowed-psc-projects=$PROJECT_ID \\\n    --availability-type=regional \\\n    --no-assign-ip \\\n    --cpu=2 \\\n    --memory=7680MB \\\n    --database-version=$DB_INSTANCE_VERSION\n    --ebable-bin-log \n```\n\nChange root password\n```bash\ngcloud sql users set-password root \\\n    --instance=$DB_INSTANCE_NAME \\\n    --prompt-for-password\n```\n\n## Get the service attachment URI\n\n```bash\nSVC_ATTACH=$(gcloud sql instances describe $DB_INSTANCE_NAME --format='value(pscServiceAttachmentLink)')\n```\n\n## Create PSC endpoint for VPC\n\n```bash\ngcloud compute addresses create psc-sql-ep \\\n    --project=$PROJECT_ID \\\n    --region=$GCP_REGION \\\n    --subnet=$SUBNET_NAME \\\n    --purpose=GCE_ENDPOINT\n```\n\nVerify the address and take note of it as it'll be used in creating DNS record\n\n```bash\ngcloud compute addresses list --filter=\"name=( 'NAME' 'psc-sql-ep')\" --project=$PROJECT_ID\n```\n\nCreate forwarding-rule\n```bash\ngcloud compute forwarding-rules create forward-sql-rule-1 \\\n    --project=$PROJECT_ID \\\n    --region=$GCP_REGION \\\n    --network=$SQL_NETWORK_NAME \\\n    --target-service-attachment=$SVC_ATTACH \\\n    --address=psc-sql-ep\n```\nList PSC endpoint to validate\n```bash\ngcloud compute forwarding-rules list --filter=\"name=( 'NAME' 'forward-sql-rule-1')\" \\\n    --regions=$GCP_REGION\n```\n\n## Configure DNS managed zone\nGet Cloud SQL DNS name\n```bash\nSQL_DNS_NAME=$(gcloud sql instances describe $DB_INSTANCE_NAME --project=$PROJECT_ID --format='value(dnsName)')\n```\n\nCreate DNS zone in each VPC\n```bash \ngcloud dns managed-zones create sql-zone \\\n    --project=$PROJECT_ID \\\n    --description=\"zone to connect to cloud sql in different vpc\" \\\n    --dns-name=$SQL_DNS_NAME \\\n    --networks=$SQL_NETWORK_NAME \\\n    --visibility=private\n```\n\nCreate DNS record for zone. IP address is from step above\n```bash\ngcloud dns record-sets create $SQL_DNS_NAME \\\n    --project=$PROJECT_ID \\\n    --type=A \\\n    --rrdatas=10.10.0.4 \\\n    --zone=sql-zone\n```\n\n## VPC connector to send Cloud Run request through\n```bash\ngcloud compute networks vpc-access connectors create $CONNECTOR \\\n    --region=$GCP_REGION \\    \n    --network=$SQL_NETWORK_NAME \\\n    --range=10.9.0.0/28 \\\n    --min-instances=2 \\\n    --max-instances=10 \\\n    --machine-type=f1-micro\n```\n\nAt this point your CloudSQL should be up and running with Private Service Connect enabled\n## Deploying Cloud Run with VPC Connector\n\nMy current directory structure\n\n```bash\n.\n├── Dockerfile\n├── app.py\n├── requirements.txt\n```\n\nDockerfile\n```bash\nFROM python:3.10-slim\n\nENV PYTHONUNBUFFERED True\n\nWORKDIR /var/www/html\nCOPY . /var/www/html/\n\nRUN pip install --no-cache-dir -r requirements.txt\n\nCMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app\n```\n\nMy requirements.txt file\n```bash\nFlask==2.0.2\ngunicorn==20.1.0\nWerkzeug==2.0.2\ncloud-sql-python-connector\npymysql\nsqlalchemy\n```\n\nMy app.py file - For Testing purposes we added the password in the code but in production we should use [Secret Manager](https://cloud.google.com/security/products/secret-manager)\n```python\nfrom flask import Flask, jsonify\nfrom google.cloud.sql.connector import Connector, IPTypes\nimport pymysql\nimport sqlalchemy\nimport os\n\napp = Flask(__name__)\n\n@app.route('/')\ndef index():\n    return \"Welcome to the Flask App!\"\n\n@app.route('/query')\ndef query_db():\n    # Initialize Cloud SQL Connector\n    connector = Connector()\n\n    def init_connection_pool(connector: Connector) -\u003e sqlalchemy.engine.Engine:\n        # Function to create a new connection\n        def getconn() -\u003e pymysql.connections.Connection:\n            conn = connector.connect(\n                \"your-project-name:us-central1:instance01\",\n                \"pymysql\",\n                ip_type=IPTypes.PSC,\n                user=\"alex\",\n                password=\"passwd01\", #Use Secret Manager in production\n                db=\"mysql\"\n            )\n            return conn\n\n        # Create a connection pool\n        pool = sqlalchemy.create_engine(\n            \"mysql+pymysql://\",\n            creator=getconn,\n        )\n        return pool\n\n    # Initialize connection pool\n    pool = init_connection_pool(connector)\n\n    with pool.connect() as db_conn:\n        try:\n            result = db_conn.execute(sqlalchemy.text(\"SELECT user, host FROM user\")).fetchall()\n            response_data = [{'user': row[0], 'host': row[1]} for row in result]\n            return jsonify(response_data)  # Return a JSON response\n        except Exception as e:\n            print(\"==========\", e)\n            return jsonify({'error': 'An error occurred'}), 500  # Return an error JSON response with HTTP status 500\n\nif __name__ == '__main__':\n    app.run(debug=True, host=\"0.0.0.0\", port=int(os.environ.get(\"PORT\", 8080)))\n```\n\nBuild the image container\n```bash\ngcloud builds submit --tag gcr.io/$PROJECT_ID/run2csqlpsc\n```\n\nDeploy Cloud Run\n```bash\ngcloud run deploy run2csqlpsc \\\n     --image gcr.io/$PROJECT_ID/run2csqlpsc \\\n     --allow-unauthenticated \\\n     --region $GCP_REGION \\\n     --platform managed \\\n     --max-instances 1 \\\n     --vpc-connector $CONNECTOR\n```\n\nCalling the Cloud Run URL followed by /query [https://---.a.run.app/query] should return something like:\n\n[{\"host\":\"\",\"user\":\"root\"},{\"host\":\"%\",\"user\":\"cloudiamgroup\"},{\"host\":\"%\",\"user\":\"cloudsqlreplica\"},{\"host\":\"%\",\"user\":\"cloudsqlsuperuser\"},{\"host\":\"%\",\"user\":\"root\"},{\"host\":\"%\",\"user\":\"root@cloudsqlproxy~10.230.7.2\"},{\"host\":\"127.0.0.1\",\"user\":\"cloudsqlexport\"},{\"host\":\"127.0.0.1\",\"user\":\"cloudsqlimport\"},{\"host\":\"127.0.0.1\",\"user\":\"cloudsqloneshot\"},{\"host\":\"127.0.0.1\",\"user\":\"root\"},{\"host\":\"::1\",\"user\":\"cloudsqlexport\"},{\"host\":\"::1\",\"user\":\"cloudsqlimport\"},{\"host\":\"::1\",\"user\":\"cloudsqloneshot\"},{\"host\":\"::1\",\"user\":\"root\"},{\"host\":\"cloudsqlproxy~10.230.7.2\",\"user\":\"alex\"},{\"host\":\"localhost\",\"user\":\"cloudsqlapplier\"},{\"host\":\"localhost\",\"user\":\"cloudsqlimport\"},{\"host\":\"localhost\",\"user\":\"cloudsqlobservabilityadmin\"},{\"host\":\"localhost\",\"user\":\"mysql.infoschema\"},{\"host\":\"localhost\",\"user\":\"mysql.session\"},{\"host\":\"localhost\",\"user\":\"mysql.sys\"},{\"host\":\"localhost\",\"user\":\"root\"}]\n\nWhich is the result of the query defined in our app.py file\n\n## Acknowledgements\n\n - I would like to extend my heartfelt gratitude to Aarmir Haroon for his invaluable assistance. Your support has been immensely appreciated.\n\n\n\n## Documentation\n\n[Configure Private Service Connect](https://cloud.google.com/sql/docs/postgres/configure-private-service-connect)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoitintl%2Fcloudrun-cloudsql-psc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoitintl%2Fcloudrun-cloudsql-psc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoitintl%2Fcloudrun-cloudsql-psc/lists"}