one by one (original) (raw)
DjangoをCloud Runにデプロイした時のメモ。
以下の記事を参考にしました。
Cloud Run での Django | Google Codelabs
今回はSQLiteを使用しているためCloud SQLは除外しています。
また、SQLiteは別で設定予定のため今回の作業には含まれません。
Cloud API を有効化
gcloud services enable
run.googleapis.com
cloudbuild.googleapis.com
secretmanager.googleapis.com
artifactregistry.googleapis.com
環境変数を設定
export PROJECT_ID=$(gcloud config get-value core/project) export REGION=us-central1
サービスアカウントを作成
gcloud iam service-accounts create cloudrun-sa
export SERVICE_ACCOUNT=$(gcloud iam service-accounts list
--filter cloudrun-sa --format "value(email)")
Artifact Registry を作成
export ARTIFACT_REGISTRY={$REGION}-docker.pkg.dev/{$PROJECT_ID}/containers
Storage バケットを作成
export GS_BUCKET_NAME={$PROJECT_ID}-media gcloud storage buckets create gs://{$GS_BUCKET_NAME} --location {$REGION}
バケットを管理する権限をサービスアカウントに付与する。
gcloud storage buckets add-iam-policy-binding gs://{$GS_BUCKET_NAME}
--member serviceAccount:{$SERVICE_ACCOUNT}
--role roles/storage.admin
Secret Managerに保存
echo GS_BUCKET_NAME="{$GS_BUCKET_NAME}" >> .env echo SECRET_KEY="$(cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 50 | head -n 1)" >> .env echo DEBUG=True >> .env
gcloud secrets create application_settings --data-file .env
サービス アカウントにこのシークレットへのアクセスを許可する。
gcloud secrets add-iam-policy-binding application_settings
--member serviceAccount:{$SERVICE_ACCOUNT} --role roles/secretmanager.secretAccessor
作成されたことを確認。
gcloud secrets versions list application_settings
rm .env
設定ファイルを作成
記事を参考に設定ファイルを作成します。
mv myproject/settings.py myproject/basesettings.py touch myproject/settings.py
myproject/settings.py
import io import os from urllib.parse import urlparse
import environ
from .basesettings import *
env = environ.Env() env.read_env(io.StringIO(os.environ.get("APPLICATION_SETTINGS", None)))
SECRET_KEY = env("SECRET_KEY")
if "myproject" not in INSTALLED_APPS: INSTALLED_APPS.append("myproject")
CLOUDRUN_SERVICE_URLS = env("CLOUDRUN_SERVICE_URLS", default=None) if CLOUDRUN_SERVICE_URLS: CSRF_TRUSTED_ORIGINS = env("CLOUDRUN_SERVICE_URLS").split(",")
ALLOWED_HOSTS = [urlparse(url).netloc for url in CSRF_TRUSTED_ORIGINS]
else: ALLOWED_HOSTS = ["*"]
DEBUG = env("DEBUG", default=False)
DATABASES = {"default": env.db("DATABASE_URL", default="sqlite:///db.sqlite3")}
GS_BUCKET_NAME = env("GS_BUCKET_NAME") STATICFILES_DIRS = [] GS_DEFAULT_ACL = "publicRead" STORAGES = { "default": { "BACKEND": "storages.backends.gcloud.GoogleCloudStorage", }, "staticfiles": { "BACKEND": "storages.backends.gcloud.GoogleCloudStorage", }, }
requirements.txt(追加)
gunicorn django-storages[google] django-environ
Procfileを作成
touch Procfile
Procfile
web: gunicorn --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 0 myproject.wsgi:application
イメージをビルドする
gcloud builds submit --pack image={$ARTIFACT_REGISTRY}/myimage
イメージ名は適宜変更します。
Cloud Runにデプロイ
gcloud run deploy django-cloudrun
--region $REGION
--image {$ARTIFACT_REGISTRY}/myimage
--set-secrets APPLICATION_SETTINGS=application_settings:latest
--service-account $SERVICE_ACCOUNT
--allow-unauthenticated
デプロイが完了して表示されたURLを選択するとDjangoのスタートページが表示されます。
変更の適用
変更があった場合は、以下の操作を行います。
- 新しいイメージをビルド
- Cloud Run を更新
gcloud builds submit --pack image=${ARTIFACT_REGISTRY}/myimage
gcloud run services update django-cloudrun
--region $REGION
--image ${ARTIFACT_REGISTRY}/myimage
.envを読み込み
ローカル環境で開発する時は、環境変数を.env
から読み込めるほうが都合がいい場合もあったのでmyproject/settings.py
に以下を追加しました。
from pathlib import Path
BASE_DIR = Path(file).resolve().parent.parent
env_path = os.path.join(BASE_DIR, '.env') if Path(env_path).is_file(): env.read_env(env_path)
前回の続きでYouTubeの動画から字幕テキストを取得するときのメモ。
import csv from youtube_transcript_api import YouTubeTranscriptApi
def get_video_transcript(video_url):
video_id = video_url.split('v=')[-1].split('&')[0]
try:
transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ja'])
transcript_text = ' '.join([entry['text'] for entry in transcript])
return transcript_text
except Exception as e:
print(f"Error retrieving transcript: {e}")
return None
def main():
video_transcripts = []
with open('video_list.csv', mode='r', encoding='utf-8') as file:
reader = csv.reader(file)
next(reader)
for row in reader:
print(f"Title: {row[0]}")
video_url = row[1]
transcript_text = get_video_transcript(video_url)
video_transcripts.append({'title': row[0], 'url': video_url, 'transcript': transcript_text})
with open('video_transcripts.csv', mode='w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerow(['title', 'url', 'transcript'])
for video_transcript in video_transcripts:
writer.writerow([video_transcript['title'], video_transcript['url'], video_transcript['transcript']])
if name == "main": main()
YouTubeのAPIを使用して動画のタイトルとURLの一覧を取得するプログラムを作成した時のメモ。
import csv from googleapiclient.discovery import build
API_KEY = ''
CHANNEL_URL=''
def get_channel_videos(channel_url):
youtube = build('youtube', 'v3', developerKey=API_KEY)
channel_id = channel_url.split('/')[-1]
videos = []
next_page_token = None
while True:
request = youtube.search().list(
part='snippet',
channelId=channel_id,
maxResults=50,
type='video',
pageToken=next_page_token
)
response = request.execute()
for item in response['items']:
video_title = item['snippet']['title']
video_url = f"https://www.youtube.com/watch?v={item['id']['videoId']}"
videos.append({'title': video_title, 'url': video_url})
next_page_token = response.get('nextPageToken')
if not next_page_token:
break
return videos
def main(): video_list = get_channel_videos(CHANNEL_URL)
with open('video_list.csv', mode='w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerow(['title', 'url'])
for video in video_list:
writer.writerow([video['title'], video['url']])
if name == "main": main()
iPhone15 Pro
毎年値段が上がるので周囲ではAndroidに転向する人も出てきましたが今年も頑張って購入しました。
Ankerのモバイルバッテリー
サイズ感がちょうど良いのとケーブルを持ち歩く必要がないので最近の普段使いはこれに落ち着きました。
aarkeの炭酸水メーカー
こういったオシャレ家電は使わなくなることのほうが多いのですが、自宅で炭酸水をつくれることが意外と便利で日常的に使う家電の仲間入りをしました。
ダンベル 10kg
体力維持レベルの運動が目的なので10kgでも充分でした。しっかりしたダンベルは数万円するので購入に勇気がいりますが、こちらは1万円台で購入しやすい価格帯ということも満足度につながりました。ダンベルが良かったので調子に乗ってベンチも買いましたが、残念ながら埃をかぶりはじめています。
耐熱ボウル
耐熱ボウルの5点セットです。最初は欲しいサイズの1点だけを予定していましたが、実際に使ってみるとそれぞれのサイズで使い分けたほうが圧倒的に料理しやすいのでセットを購入して良かったと思います。
マキネッタ
夏場にアイスカフェラテをつくるのに大活躍しました。手入れも大雑把でいいので性分に合っていました。豆を自分で挽くか悩みましたが、面倒になり使用する機会が減ると思ったので、豆を購入した時にお店で挽いてもらいました。
RICOH GR IIIx
サイズ感と重さと軽さが自分の生活に合っていました。iPhone15 Pro購入以降は持ち出す回数が減りましたが、旅行に行った時などにGRを使用しています。数年前に思い切って購入したミラーレス一眼は、今年は使用する機会がなかったので来年売却するか悩んでいます。
漫画
最近読んで面白い作品でした。
PS5
年末年始のお供にホグワーツ・レガシーと合わせて購入しました。ゲームはエンタメの最先端のひとつであることを学びました。
Rustでdotenvのcrateはメンテナンスが行われていないらしく以下の記事を参考にdotenvyを使用しました。
$ cargo add dotenvy
適当に.envを作成
FOO=bar
use dotenvy::dotenv; use std::env;
fn main() { dotenv().expect(".env file not found");
let val = env::var("FOO").expect("FOO not set");
println!("Foo: {val}");
}
$ cargo run Foo: bar
Windows環境での作業が必要になったので、リモートデスクトップでMacからWindowsを使用するための準備を行いました。
リモートデスクトップ接続するためのアプリはいくつか候補がありましたが、 今回は用途に合っていた「Microsoft Remote Desktop」を選びました。
Windows 11 Homeを使用していましたが、Microsoft Remote Desktopで接続するにはProエディションにする必要があったため Windows 11 Proを購入しました。
普段Macを使用しているので、Microsoft Remote Desktopで接続した時のWindowsキーやIMEの切り替え操作に馴染めず、 Karabinerに以下のルールを追加しました。
- 左のcommandキーをWinのControlキー
- 右のcommandキーをWinのIME切り替え
{ "title": "Custom rules for Remote Desktop", "rules": [ { "description": "Swap left_control and left_command in Remote Desktop", "manipulators": [ { "type": "basic", "from": { "key_code": "left_command", "modifiers": { "optional": ["any"] } }, "to": [ { "key_code": "left_control" } ], "conditions": [ { "type": "frontmost_application_if", "bundle_identifiers": [ "^com\.microsoft\.rdc\.macos$" ] } ] } ] }, { "description": "Toggle IME with right_command in Remote Desktop", "manipulators": [ { "type": "basic", "from": { "key_code": "right_command", "modifiers": { "optional": ["any"] } }, "to": [ { "key_code": "grave_accent_and_tilde", "modifiers": ["right_alt"] } ], "conditions": [ { "type": "frontmost_application_if", "bundle_identifiers": [ "^com\.microsoft\.rdc\.macos$" ] } ] } ] } ] }
さくらVPSにPostgresqlをインストールした時のメモ
yum update -y
yum install -y https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm
yum install -y postgresql96-server postgresql96-contrib postgresql96-devel
psql --version
psql (PostgreSQL) 9.6.11
初期化
export PGSETUP_INITDB_OPTIONS="--encoding=UTF-8 --no-locale"
/usr/pgsql-9.6/bin/postgresql96-setup initdb
systemctl enable postgresql-9.6
systemctl start postgresql-9.6
認証方法を変更
$ sudo vim /var/lib/pgsql/9.6/data/pg_hba.conf
peerをtrustに、identをmd5に変更
"local" is for Unix domain socket connections only
local all all trust
IPv4 local connections:
host all all 127.0.0.1/32 md5
IPv6 local connections:
host all all ::1/128 md5