จัดเก็บตัวแปรสภาพแวดล้อมใน GAE อย่างปลอดภัยด้วย app.yaml


101

ฉันต้องการจัดเก็บคีย์ API และข้อมูลที่ละเอียดอ่อนอื่น ๆapp.yamlเป็นตัวแปรสภาพแวดล้อมสำหรับการปรับใช้บน GAE ปัญหาเกี่ยวกับเรื่องนี้คือถ้าฉันกดapp.yamlไปที่ GitHub ข้อมูลนี้จะกลายเป็นสาธารณะ (ไม่ดี) ฉันไม่ต้องการเก็บข้อมูลไว้ในที่เก็บข้อมูลเนื่องจากไม่เหมาะกับโครงการ แต่ฉันต้องการเปลี่ยนค่าจากไฟล์ที่แสดงอยู่ใน.gitignoreการปรับใช้แต่ละแอป

นี่คือไฟล์ app.yaml ของฉัน:

application: myapp
version: 3 
runtime: python27
api_version: 1
threadsafe: true

libraries:
- name: webapp2
  version: latest
- name: jinja2
  version: latest

handlers:
- url: /static
  static_dir: static

- url: /.*
  script: main.application  
  login: required
  secure: always
# auth_fail_action: unauthorized

env_variables:
  CLIENT_ID: ${CLIENT_ID}
  CLIENT_SECRET: ${CLIENT_SECRET}
  ORG: ${ORG}
  ACCESS_TOKEN: ${ACCESS_TOKEN}
  SESSION_SECRET: ${SESSION_SECRET}

ความคิดใด ๆ ?


77
ฉันหวังว่า GAE จะเพิ่มตัวเลือกในการตั้งค่าอินสแตนซ์ env vars ผ่านคอนโซลนักพัฒนาซอฟต์แวร์ (เหมือนกับ PaaS อื่น ๆ ที่ฉันคุ้นเคย)
Spain Train

5
คุณสามารถใช้พื้นที่เก็บข้อมูล โปรดอ้างอิงคำตอบนี้: stackoverflow.com/a/35254560/1027846
Mustafa İlhan

ขยายความคิดเห็นของ mustilica ด้านบนเกี่ยวกับการใช้พื้นที่เก็บข้อมูล ดูคำตอบของฉันด้านล่างสำหรับรหัสที่ผมใช้ในโครงการของฉันที่จะทำเช่นนี้: stackoverflow.com/a/35261091#35261091 มีผลให้คุณแก้ไขตัวแปรสภาพแวดล้อมจากคอนโซลนักพัฒนาซอฟต์แวร์และค่าตัวยึดจะถูกสร้างขึ้นโดยอัตโนมัติ
Martin Omander

ขอบคุณ mustilica และ Martin เราใช้วิธีการจัดเก็บข้อมูลมาระยะหนึ่งแล้วและฉันยอมรับว่าเป็นวิธีแก้ปัญหาที่ดีที่สุดสำหรับปัญหานี้ การตั้งค่า CI / CD ทำได้ง่ายกว่าวิธีไฟล์ json, IMO
รถไฟสเปน

1
2019 และ GAE ยังไม่ได้แก้ไขปัญหานี้: /
Josh Noe

คำตอบ:


55

หากเป็นข้อมูลที่ละเอียดอ่อนคุณไม่ควรเก็บไว้ในซอร์สโค้ดเนื่องจากจะถูกตรวจสอบในการควบคุมแหล่งที่มา คนที่ไม่ถูกต้อง (ภายในหรือภายนอกองค์กรของคุณ) อาจพบได้ที่นั่น นอกจากนี้สภาพแวดล้อมการพัฒนาของคุณอาจใช้ค่ากำหนดค่าที่แตกต่างจากสภาพแวดล้อมการผลิตของคุณ หากค่าเหล่านี้ถูกเก็บไว้ในโค้ดคุณจะต้องรันโค้ดที่แตกต่างกันในการพัฒนาและการผลิตซึ่งเป็นวิธีที่ยุ่งและไม่ดี

ในโครงการของฉันฉันใส่ข้อมูลการกำหนดค่าในที่เก็บข้อมูลโดยใช้คลาสนี้:

from google.appengine.ext import ndb

class Settings(ndb.Model):
  name = ndb.StringProperty()
  value = ndb.StringProperty()

  @staticmethod
  def get(name):
    NOT_SET_VALUE = "NOT SET"
    retval = Settings.query(Settings.name == name).get()
    if not retval:
      retval = Settings()
      retval.name = name
      retval.value = NOT_SET_VALUE
      retval.put()
    if retval.value == NOT_SET_VALUE:
      raise Exception(('Setting %s not found in the database. A placeholder ' +
        'record has been created. Go to the Developers Console for your app ' +
        'in App Engine, look up the Settings record with name=%s and enter ' +
        'its value in that record\'s value field.') % (name, name))
    return retval.value

แอปพลิเคชันของคุณจะทำสิ่งนี้เพื่อรับค่า:

API_KEY = Settings.get('API_KEY')

หากมีค่าสำหรับคีย์นั้นในที่เก็บข้อมูลคุณจะได้รับ หากไม่มีระบบจะสร้างเรกคอร์ดตัวยึดตำแหน่งและข้อยกเว้นจะถูกโยนทิ้ง ข้อยกเว้นจะเตือนให้คุณไปที่ Developers Console และอัปเดตระเบียนตัวยึด

ฉันพบว่าสิ่งนี้ไม่สามารถคาดเดาได้จากการตั้งค่าการกำหนดค่า หากคุณไม่แน่ใจว่าจะตั้งค่า config อะไรแค่รันโค้ดแล้วมันจะบอกคุณเอง!

โค้ดด้านบนใช้ไลบรารี ndb ซึ่งใช้ memcache และ datastore ภายใต้ประทุนดังนั้นจึงรวดเร็ว


อัปเดต:

jelderถามถึงวิธีค้นหาค่า Datastore ในคอนโซล App Engine และตั้งค่า นี่คือวิธี:

  1. ไปที่https://console.cloud.google.com/datastore/

  2. เลือกโครงการของคุณที่ด้านบนสุดของหน้าหากยังไม่ได้เลือก

  3. ในชนิดกล่องแบบหล่นลงเลือกการตั้งค่า

  4. หากคุณรันโค้ดด้านบนคีย์ของคุณจะปรากฏขึ้น พวกเขาทั้งหมดจะมีค่าไม่ได้ตั้งค่า คลิกแต่ละอันแล้วตั้งค่า

หวังว่านี่จะช่วยได้!

การตั้งค่าของคุณสร้างโดยคลาสการตั้งค่า

คลิกเพื่อแก้ไข

ป้อนมูลค่าที่แท้จริงและบันทึก


3
จากคำตอบที่ให้มาทั้งหมดนี้ดูเหมือนจะใกล้เคียงที่สุดกับวิธีที่ Heroku จัดการกับสิ่งต่างๆ ค่อนข้างใหม่สำหรับ GAE ฉันไม่ค่อยเข้าใจว่าใน Developers Console จะหาระเบียนตัวยึดตำแหน่งได้จากที่ใด คุณช่วยอธิบายหรือขอคะแนนโบนัสโพสต์ภาพหน้าจอได้ไหม
jelder

3
เขื่อน ~ …เนื่องจาก gcloud ดูแย่มากที่ต้องใช้บริการอื่นสำหรับความต้องการเฉพาะนี้ นอกจากนั้น Google ยังมีแนวทาง "100% -herokuish" สำหรับ env vars ภายในฟังก์ชัน firebase แต่ไม่ใช้สำหรับฟังก์ชัน gcloud (อย่างน้อยก็ไม่มีเอกสาร ... ถ้าฉันไม่ผิด)
Ben

2
นี่คือส่วนสำคัญตามแนวทางของคุณที่เพิ่มความเป็นเอกลักษณ์และตัวแปรทางเลือกสำรอง - gist.github.com/SpainTrain/6bf5896e6046a5d9e7e765d0defc8aa8
รถไฟสเปน

3
ฟังก์ชั่น @Ben Non-Firebase รองรับ env vars (ตอนนี้เป็นอย่างน้อย)
NReilingh

3
@obl - แอป App Engine จะได้รับการตรวจสอบสิทธิ์โดยอัตโนมัติไปยังที่เก็บข้อมูลของตนเองโดยไม่จำเป็นต้องมีรายละเอียดการตรวจสอบสิทธิ์ มันค่อนข้างเรียบร้อย :-)
Martin Omander

59

วิธีนี้ทำได้ง่าย แต่อาจไม่เหมาะกับทุกทีม

ขั้นแรกให้ใส่ตัวแปรสภาพแวดล้อมในenv_variables.yamlเช่น

env_variables:
  SECRET: 'my_secret'

จากนั้นรวมสิ่งนี้env_variables.yamlไว้ในไฟล์app.yaml

includes:
  - env_variables.yaml

สุดท้ายเพิ่มenv_variables.yamlto เพื่อ.gitignoreไม่ให้ตัวแปรลับมีอยู่ในที่เก็บ

ในกรณีนี้env_variables.yamlจำเป็นต้องใช้ร่วมกันระหว่างผู้จัดการการปรับใช้


2
เพียงเพื่อเพิ่มสิ่งที่อาจไม่ชัดเจนสำหรับบางอย่างตัวแปรสภาพแวดล้อมของคุณจะถูกพบในprocess.env.MY_SECRET_KEYและหากคุณต้องการตัวแปรสภาพแวดล้อมเหล่านี้ในสภาพแวดล้อม dev ในพื้นที่ของคุณคุณสามารถใช้dotenvแพ็คเกจโหนดได้
Dave Kiss

4
วิธีที่จะenv_variables.yamlไปถึงอินสแตนซ์ทั้งหมดเป็นส่วนที่ขาดหายไปของปริศนา
Christopher Oezbek

1
นอกจากนี้: จะใช้ในพื้นที่ได้อย่างไร?
Christopher Oezbek

@ChristopherOezbek 1. วิธีการปรับใช้? เพียงใช้gcloud app deployตามปกติเพื่อปรับใช้กับ Google Cloud 2. วิธีการตั้งค่าตัวแปรสภาพแวดล้อมที่เป็นความลับในเครื่อง? มีมากมายหลายวิธี คุณสามารถใช้exportในพรอมต์คำสั่งหรือใช้เครื่องมือใด ๆ เช่นที่ @DaveKiss แนะนำ
Shih-Wen Su

1
นี่คือทางออกที่ง่ายที่สุด os.environ.get('SECRET')ความลับที่สามารถเข้าถึงได้ในการประยุกต์ใช้ของคุณผ่านทาง
Quinn Comendant

20

วิธีการของฉันคือการเก็บความลับของลูกค้าเฉพาะภายในแอป App Engine ตัวเอง ความลับของไคลเอ็นต์ไม่ได้อยู่ในการควบคุมแหล่งที่มาหรือบนคอมพิวเตอร์ภายในเครื่องใด ๆ สิ่งนี้มีประโยชน์ที่ผู้ทำงานร่วมกันของ App Engine สามารถปรับใช้การเปลี่ยนแปลงโค้ดได้โดยไม่ต้องกังวลเกี่ยวกับความลับของไคลเอ็นต์

ฉันเก็บความลับของไคลเอ็นต์ไว้ใน Datastore โดยตรงและใช้ Memcache เพื่อปรับปรุงเวลาในการตอบสนองในการเข้าถึงความลับ ต้องสร้างเอนทิตี Datastore เพียงครั้งเดียวและจะยังคงมีอยู่ตลอดการใช้งานในอนาคต แน่นอนว่าคุณสามารถใช้คอนโซล App Engine เพื่ออัปเดตเอนทิตีเหล่านี้ได้ตลอดเวลา

มีสองตัวเลือกในการสร้างเอนทิตีแบบครั้งเดียว:

  • ใช้เชลล์แบบโต้ตอบApp Engine Remote APIเพื่อสร้างเอนทิตี
  • สร้างตัวจัดการเฉพาะผู้ดูแลระบบที่จะเริ่มต้นเอนทิตีด้วยค่าดัมมี่ เรียกใช้ตัวจัดการผู้ดูแลระบบนี้ด้วยตนเองจากนั้นใช้คอนโซล App Engine เพื่ออัปเดตเอนทิตีด้วยความลับไคลเอ็นต์ที่ใช้งานจริง

7
ไม่ซับซ้อน แต่อย่างใด ขอบคุณแอพเอ็นจิ้น
Courtsimas

19

สิ่งนี้ไม่ได้เกิดขึ้นเมื่อคุณโพสต์ แต่สำหรับใครก็ตามที่สะดุดที่นี่ตอนนี้ Google มีบริการที่เรียกว่าSecret Managerผู้จัดการลับ

เป็นบริการ REST ที่เรียบง่าย (แน่นอนว่ามี SDK ห่อไว้) เพื่อจัดเก็บความลับของคุณในตำแหน่งที่ปลอดภัยบนแพลตฟอร์มคลาวด์ของ Google นี่เป็นแนวทางที่ดีกว่าที่เก็บข้อมูลโดยต้องมีขั้นตอนเพิ่มเติมในการดูความลับที่จัดเก็บไว้และมีรูปแบบการอนุญาตที่ละเอียดยิ่งขึ้นคุณสามารถรักษาความลับแต่ละรายการให้แตกต่างกันไปสำหรับแง่มุมต่างๆในโครงการของคุณได้หากต้องการ

มีการกำหนดเวอร์ชันเพื่อให้คุณสามารถจัดการกับการเปลี่ยนแปลงรหัสผ่านได้อย่างง่ายดายรวมทั้งแบบสอบถามและเลเยอร์การจัดการที่มีประสิทธิภาพช่วยให้คุณค้นพบและสร้างความลับในรันไทม์ได้หากจำเป็น

Python SDK

ตัวอย่างการใช้งาน:

from google.cloud import secretmanager_v1beta1 as secretmanager

secret_id = 'my_secret_key'
project_id = 'my_project'
version = 1    # use the management tools to determine version at runtime

client = secretmanager.SecretManagerServiceClient()

secret_path = client.secret_verion_path(project_id, secret_id, version)
response = client.access_secret_version(secret_path)
password_string = response.payload.data.decode('UTF-8')

# use password_string -- set up database connection, call third party service, whatever

3
นี่ควรเป็นคำตอบใหม่ที่ถูกต้อง Secret Manager ยังอยู่ในรุ่นเบต้า แต่นี่เป็นแนวทางในการทำงานกับตัวแปรสภาพแวดล้อม
King Leon

@KingLeon จะใช้วิธีนี้ต้อง refactor พวงos.getenv('ENV_VAR')?
Alejandro

SECRET_KEY = env('SECRET_KEY', default=access_secret_version(GOOGLE_CLOUD_PROJECT_ID, 'SECRET_KEY', 1))ฉันใส่รหัสคล้ายกับข้างต้นในการทำงานแล้วผมใช้สิ่งที่ต้องการ การตั้งค่าเริ่มต้นเพื่อใช้access_secret_version
King Leon

นอกจากนี้ฉันกำลังใช้ django-environ github.com/joke2k/django-environ
King Leon

ฉันต้องการถามคำถามโง่ ๆ แต่สิ่งที่คุณเรียกsecret_id = 'my_secret_key'ไม่อยู่ในการควบคุมเวอร์ชันของคุณหรือไม่?
dierre

16

วิธีที่ดีที่สุดคือเก็บคีย์ไว้ในไฟล์ client_secrets.json และแยกไม่ให้อัปโหลดไปยัง git โดยระบุไว้ในไฟล์. gitignore หากคุณมีคีย์ที่แตกต่างกันสำหรับสภาพแวดล้อมที่แตกต่างกันคุณสามารถใช้ app_identity api เพื่อกำหนดว่า id ของแอปคืออะไรและโหลดอย่างเหมาะสม

มีตัวอย่างที่ค่อนข้างครอบคลุมที่นี่ -> https://developers.google.com/api-client-library/python/guide/aaa_client_secrets https://developers.google.com/api-client-library/python/guide/aaa_client_secrets

นี่คือตัวอย่างโค้ด:

# declare your app ids as globals ...
APPID_LIVE = 'awesomeapp'
APPID_DEV = 'awesomeapp-dev'
APPID_PILOT = 'awesomeapp-pilot'

# create a dictionary mapping the app_ids to the filepaths ...
client_secrets_map = {APPID_LIVE:'client_secrets_live.json',
                      APPID_DEV:'client_secrets_dev.json',
                      APPID_PILOT:'client_secrets_pilot.json'}

# get the filename based on the current app_id ...
client_secrets_filename = client_secrets_map.get(
    app_identity.get_application_id(),
    APPID_DEV # fall back to dev
    )

# use the filename to construct the flow ...
flow = flow_from_clientsecrets(filename=client_secrets_filename,
                               scope=scope,
                               redirect_uri=redirect_uri)

# or, you could load up the json file manually if you need more control ...
f = open(client_secrets_filename, 'r')
client_secrets = json.loads(f.read())
f.close()

2
ไปในทิศทางที่ถูกต้องอย่างแน่นอน แต่สิ่งนี้ไม่ได้แก้ปัญหาการแลกเปลี่ยนค่าในapp.yamlการปรับใช้แอป มีความคิดใดบ้าง
เบ็น

1
ดังนั้นให้มีไฟล์ client_secrets ที่แตกต่างกันสำหรับแต่ละสภาพแวดล้อม เช่น client_secrets_live.json, client_secrets_dev.json, client_secrets_pilot.json เป็นต้นจากนั้นใช้ตรรกะ python เพื่อกำหนดเซิร์ฟเวอร์ที่คุณอยู่และโหลดไฟล์ json ที่เหมาะสม app_identity.get_application_id () วิธีการอาจมีประโยชน์ในการตรวจหาเซิร์ฟเวอร์ที่คุณอยู่โดยอัตโนมัติ นี่คือสิ่งที่คุณหมายถึง?
Gwyn Howell

@BenGrunfeld ดูคำตอบของฉัน วิธีแก้ปัญหาของฉันทำอย่างนี้ ฉันไม่เห็นว่าคำตอบนี้จะแก้ปัญหาได้อย่างไร ฉันคิดว่าเป้าหมายคือเก็บการกำหนดค่าที่เป็นความลับออกจากคอมไพล์และใช้ git เป็นส่วนหนึ่งของการปรับใช้ ไฟล์นี้ยังคงต้องอยู่ที่ใดที่หนึ่งและถูกส่งเข้าสู่กระบวนการปรับใช้ นี่อาจเป็นสิ่งที่คุณทำในแอพของคุณ แต่คุณจะใช้เทคนิคที่ฉันเน้นไว้บางทีอาจจะเก็บไว้ในไฟล์อื่นหากคุณต้องการใช้แอพนี้เทียบกับ app.yaml ถ้าฉันเข้าใจคำถามก็จะคล้ายกับการจัดส่งแอปโอเพนซอร์สพร้อมกับรหัสลับหรือผลิตภัณฑ์สำหรับลูกค้าที่แท้จริงของผู้สร้างห้องสมุด สำคัญ.
therewillbesnacks

1
ฉันใช้เวลาสักพักในการทำความเข้าใจ แต่ฉันคิดว่านี่เป็นแนวทางที่ถูกต้อง คุณไม่ได้ผสมการตั้งค่าแอปพลิเคชัน ( app.yaml) กับคีย์ลับและข้อมูลที่เป็นความลับและสิ่งที่ฉันชอบมากก็คือคุณกำลังใช้เวิร์กโฟลว์ของ Google เพื่อทำงานให้สำเร็จ ขอบคุณ @GwynHowell =)
เบ็น

1
วิธีการที่คล้ายกันคือการวางไฟล์ JSON ในตำแหน่งที่ทราบในที่เก็บข้อมูล GCS เริ่มต้นของแอป ( cloud.google.com/appengine/docs/standard/python/… )
รถไฟสเปน

15

โซลูชันนี้อาศัย appcfg.py ที่เลิกใช้แล้ว

คุณสามารถใช้ตัวเลือกบรรทัดคำสั่ง -E ของ appcfg.py เพื่อตั้งค่าตัวแปรสภาพแวดล้อมเมื่อคุณปรับใช้แอปของคุณกับ GAE (อัปเดต appcfg.py)

$ appcfg.py
...
-E NAME:VALUE, --env_variable=NAME:VALUE
                    Set an environment variable, potentially overriding an
                    env_variable value from app.yaml file (flag may be
                    repeated to set multiple variables).
...

คุณสามารถสอบถามตัวแปรสภาพแวดล้อมเหล่านั้นได้หรือไม่หลังจากปรับใช้ (ฉันหวังว่าจะไม่)
Ztyx

มีวิธีส่งผ่านตัวแปรสภาพแวดล้อมในลักษณะนี้โดยใช้gcloudยูทิลิตี้หรือไม่?
Trevor

6

คำตอบส่วนใหญ่ล้าสมัย การใช้ Google cloud datastore นั้นแตกต่างไปเล็กน้อยในตอนนี้ https://cloud.google.com/python/getting-started/using-cloud-datastore

นี่คือตัวอย่าง:

from google.cloud import datastore
client = datastore.Client()
datastore_entity = client.get(client.key('settings', 'TWITTER_APP_KEY'))
connection_string_prod = datastore_entity.get('value')

สิ่งนี้ถือว่าชื่อเอนทิตีคือ 'TWITTER_APP_KEY' ชนิดคือ 'การตั้งค่า' และ 'ค่า' เป็นคุณสมบัติของเอนทิตี TWITTER_APP_KEY


4

คุณควรเข้ารหัสตัวแปรด้วย google kms และฝังไว้ในซอร์สโค้ดของคุณ ( https://cloud.google.com/kms/ )

echo -n the-twitter-app-key | gcloud kms encrypt \
> --project my-project \
> --location us-central1 \
> --keyring THEKEYRING \
> --key THECRYPTOKEY \
> --plaintext-file - \
> --ciphertext-file - \
> | base64

ใส่ค่าที่มีสัญญาณรบกวน (เข้ารหัสและเข้ารหัส base64) ลงในตัวแปรสภาพแวดล้อมของคุณ (ในไฟล์ yaml)

รหัส pythonish บางอย่างเพื่อให้คุณเริ่มถอดรหัส

kms_client = kms_v1.KeyManagementServiceClient()
name = kms_client.crypto_key_path_path("project", "global", "THEKEYRING", "THECRYPTOKEY")

twitter_app_key = kms_client.decrypt(name, base64.b64decode(os.environ.get("TWITTER_APP_KEY"))).plaintext

3

ดูเหมือนว่าคุณสามารถทำได้หลายวิธี เรามีปัญหาที่คล้ายกันและดำเนินการดังต่อไปนี้ (ปรับให้เข้ากับกรณีการใช้งานของคุณ):

  • สร้างไฟล์ที่เก็บค่าไดนามิก app.yaml และวางไว้บนเซิร์ฟเวอร์ที่ปลอดภัยในสภาพแวดล้อมการสร้างของคุณ หากคุณหวาดระแวงจริงๆคุณสามารถเข้ารหัสค่าแบบไม่สมมาตรได้ คุณสามารถเก็บสิ่งนี้ไว้ใน repo ส่วนตัวได้หากคุณต้องการการควบคุมเวอร์ชัน / การดึงแบบไดนามิกหรือเพียงแค่ใช้เชลล์สคริปต์เพื่อคัดลอก / ดึงจากตำแหน่งที่เหมาะสม
  • ดึงจาก git ระหว่างสคริปต์การปรับใช้
  • หลังจากการดึงคอมไพล์ให้แก้ไข app.yaml โดยการอ่านและเขียนใน python โดยใช้ไลบรารี yaml

วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการใช้เซิร์ฟเวอร์รวมอย่างต่อเนื่องเช่นฮัดสัน , ไม้ไผ่หรือเจนกินส์เจนกินส์เพียงเพิ่มปลั๊กอินขั้นตอนสคริปต์หรือเวิร์กโฟลว์ที่ทำตามรายการข้างต้นทั้งหมดที่ฉันกล่าวถึง คุณสามารถส่งผ่านตัวแปรสภาพแวดล้อมที่กำหนดค่าไว้ใน Bamboo ได้เช่น

โดยสรุปเพียงแค่พุชค่าในระหว่างขั้นตอนการสร้างของคุณในสภาพแวดล้อมที่คุณเข้าถึงได้เท่านั้น หากคุณยังไม่ได้สร้างงานสร้างโดยอัตโนมัติคุณควรจะเป็น

อีกทางเลือกหนึ่งคือสิ่งที่คุณพูดใส่ไว้ในฐานข้อมูล หากเหตุผลของคุณที่ไม่ทำเช่นนั้นคือสิ่งต่างๆช้าเกินไปเพียงแค่กดค่าลงใน memcache เป็นแคชชั้นที่ 2 แล้วตรึงค่าไว้ที่อินสแตนซ์เป็นแคชชั้นหนึ่ง หากค่าสามารถเปลี่ยนแปลงได้และคุณจำเป็นต้องอัปเดตอินสแตนซ์โดยไม่ต้องรีบูตเพียงแค่เก็บแฮชที่คุณสามารถตรวจสอบเพื่อให้ทราบว่ามีการเปลี่ยนแปลงหรือทริกเกอร์เมื่อใดก็ตามที่คุณทำเปลี่ยนแปลงค่า ที่ควรจะเป็น


1
FWIW แนวทางนี้เป็นไปตามปัจจัยกำหนดค่าในแนวทางแอป 12 Factor อย่างใกล้ชิดที่สุด ( 12factor.net )
รถไฟสเปน

3

@ สัน F ของคำตอบขึ้นอยู่กับการใช้งาน Google Datastore อยู่ใกล้ แต่รหัสเป็นบิตล้าสมัยตามการใช้งานตัวอย่างในเอกสารห้องสมุด นี่คือตัวอย่างที่ใช้ได้ผลสำหรับฉัน:

from google.cloud import datastore

client = datastore.Client('<your project id>')
key = client.key('<kind e.g settings>', '<entity name>') # note: entity name not property
# get by key for this entity
result = client.get(key)
print(result) # prints all the properties ( a dict). index a specific value like result['MY_SECRET_KEY'])

ส่วนหนึ่งได้รับแรงบันดาลใจจากโพสต์ขนาดกลางนี้


2

แค่อยากทราบว่าฉันแก้ปัญหานี้ใน javascript / nodejs ได้อย่างไร สำหรับการพัฒนาท้องถิ่นฉันใช้แพ็คเกจ npm 'dotenv' ซึ่งโหลดตัวแปรสภาพแวดล้อมจากไฟล์. env ไปยัง process.env เมื่อฉันเริ่มใช้ GAE ฉันได้เรียนรู้ว่าต้องตั้งค่าตัวแปรสภาพแวดล้อมในไฟล์ "app.yaml" ฉันไม่ต้องการใช้ 'dotenv' สำหรับการพัฒนาในพื้นที่และ 'app.yaml' สำหรับ GAE (และทำซ้ำตัวแปรสภาพแวดล้อมของฉันระหว่างสองไฟล์) ดังนั้นฉันจึงเขียนสคริปต์เล็กน้อยที่โหลดตัวแปรสภาพแวดล้อม app.yaml เข้าสู่กระบวนการ .env เพื่อการพัฒนาท้องถิ่น. หวังว่านี่จะช่วยใครบางคน:

yaml_env.js:

(function () {
    const yaml = require('js-yaml');
    const fs = require('fs');
    const isObject = require('lodash.isobject')

    var doc = yaml.safeLoad(
        fs.readFileSync('app.yaml', 'utf8'), 
        { json: true }
    );

    // The .env file will take precedence over the settings the app.yaml file
    // which allows me to override stuff in app.yaml (the database connection string (DATABASE_URL), for example)
    // This is optional of course. If you don't use dotenv then remove this line:
    require('dotenv/config');

    if(isObject(doc) && isObject(doc.env_variables)) {
        Object.keys(doc.env_variables).forEach(function (key) {
            // Dont set environment with the yaml file value if it's already set
            process.env[key] = process.env[key] || doc.env_variables[key]
        })
    }
})()

ตอนนี้รวมไฟล์นี้ไว้ในโค้ดของคุณโดยเร็วที่สุดเท่าที่จะเป็นไปได้และคุณทำเสร็จแล้ว:

require('../yaml_env')

ยังคงเป็นเช่นนี้อยู่หรือไม่? เพราะฉันใช้.envไฟล์ที่มีตัวแปรลับ ฉันไม่ได้ทำซ้ำในapp.yamlไฟล์ของฉันและโค้ดที่ปรับใช้ของฉันก็ยังใช้งานได้ ฉันกังวลว่าจะเกิดอะไรขึ้นกับ.envไฟล์ในระบบคลาวด์ มันถูกเข้ารหัสหรืออะไร? ฉันจะแน่ใจได้อย่างไรว่าไม่มีใครเข้าถึง.envตัวแปรของไฟล์gcloud เมื่อปรับใช้แล้ว
กัส

สิ่งนี้ไม่จำเป็นเลยเนื่องจาก GAE จะเพิ่มตัวแปรทั้งหมดที่กำหนดไว้ในไฟล์ app.yaml ไปยังสภาพแวดล้อมโหนดโดยอัตโนมัติ โดยทั่วไปสิ่งนี้เหมือนกับที่ dotenv ทำกับตัวแปรที่กำหนดในแพ็คเกจ. env แต่ฉันสงสัยว่าคุณต้องตั้งค่าซีดีอย่างไรเนื่องจากคุณไม่สามารถดัน app.yaml ด้วย env vars ไปยัง VCS หรือไปป์ไลน์ ...
Jornve

1

ขยายคำตอบของ Martin

from google.appengine.ext import ndb

class Settings(ndb.Model):
    """
    Get sensitive data setting from DataStore.

    key:String -> value:String
    key:String -> Exception

    Thanks to: Martin Omander @ Stackoverflow
    https://stackoverflow.com/a/35261091/1463812
    """
    name = ndb.StringProperty()
    value = ndb.StringProperty()

    @staticmethod
    def get(name):
        retval = Settings.query(Settings.name == name).get()
        if not retval:
            raise Exception(('Setting %s not found in the database. A placeholder ' +
                             'record has been created. Go to the Developers Console for your app ' +
                             'in App Engine, look up the Settings record with name=%s and enter ' +
                             'its value in that record\'s value field.') % (name, name))
        return retval.value

    @staticmethod
    def set(name, value):
        exists = Settings.query(Settings.name == name).get()
        if not exists:
            s = Settings(name=name, value=value)
            s.put()
        else:
            exists.value = value
            exists.put()

        return True

1

มีแพ็คเกจ pypi ที่เรียกว่าgae_envที่ให้คุณบันทึกตัวแปรสภาพแวดล้อมของ appengine ใน Cloud Datastore ภายใต้ฝากระโปรงยังใช้ Memcache จึงรวดเร็ว

การใช้งาน:

import gae_env

API_KEY = gae_env.get('API_KEY')

หากมีค่าสำหรับคีย์นั้นในที่เก็บข้อมูลระบบจะส่งคืน หากไม่มี__NOT_SET__จะมีการสร้างเรกคอร์ดตัวยึดตำแหน่งและValueNotSetErrorจะถูกโยนทิ้ง ข้อยกเว้นจะเตือนให้คุณไปที่Developers Consoleและอัปเดตระเบียนตัวยึด


คล้ายกับคำตอบของ Martin นี่คือวิธีอัปเดตค่าสำหรับคีย์ใน Datastore:

  1. ไปที่ส่วน Datastoreในคอนโซลนักพัฒนา

  2. เลือกโครงการของคุณที่ด้านบนสุดของหน้าหากยังไม่ได้เลือก

  3. ในชนิดGaeEnvSettingsกล่องแบบหล่นลงเลือก

  4. __NOT_SET__คีย์ที่มีข้อยกเว้นถูกยกขึ้นจะมีค่า

การตั้งค่าของคุณสร้างโดยคลาสการตั้งค่า

คลิกเพื่อแก้ไข

ป้อนมูลค่าที่แท้จริงและบันทึก


ไปที่หน้า GitHub ของแพ็คเกจเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้งาน / การกำหนดค่า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.