概要
Oracle Cloud Infrastructure(OCI)のContainer Instances は、Kubernetes(OKE)のような複雑なオーケストレーションを必要とせず、サーバーレスで手軽にコンテナを実行できる非常に便利なサービスです。
単一のコンテナを動かすだけであれば非常にシンプルなContainer Instancesですが、実運用を見据えたサーバーを構築しようとすると制約や課題に直面します
例えば
- 永続ディスクとしてNFS(File Storage)を直接マウントできない
外部ストレージを直接マウントする機能をサポートいないため代替案を検討する必要がある - 標準ログだけでは実運用のモニタリングが不十分
Container Instancesはコンテナの標準出力をコンソール上に表示・集約してくれますが、長期間のログ保存やログ監視基盤連携するためには外部転送する仕組みが不可欠です。
これらの課題を解決するためのマルチコンテナ構成を検証しました
構成
以下の 3コンテナ構成で環境を構築します
-
メインコンテナ(Appl): 今回は検証用としてNginxを使用します
-
サイドカー1(Rclone):
Object Storageからデータを取得し、Nginxと共有します -
サイドカー2(Fluent Bit):
Nginxが出力したログファイルを外部のSyslogサーバーへ転送します
コンテナ間のファイルやログの受け渡しには、Container Instancesがサポートする一時ボリューム EmptyDir(EMPTY_DIR) を使用します
事前準備
Container Instancesを構築する前の事前準備です
- Terraform環境のセットアップ
OCI CLI等別の手段でもContainer Instances作成可能です - Object Storageにデータをアップロード
今回はWebコンテンツをデータとしています
OCI環境準備
Container Instances作成/実行のための環境準備です
- ネットワーク(VCN/Subnet)の作成
Container Instancesが起動するネットワーク - 動的グループおよびIAMポリシーの作成
Container InstancesがObject Storageからオブジェクトを取得するためのポリシー
## Replace << >> with the appropriate value
Dynamic-group
container-instance-dynamic-group
ALL {resource.type = 'containerinstance', resource.compartment.id = '<<compartment OCID>>'}
Policy
Allow dynamic-group container-instance-dynamic-group to read objects in compartment <<compartment>> where target.bucket.name = '<<Object Storage Bucket>>'
Terraform環境が導入されたインスタンスからContainer Instancesを起動するためのポリシー
## Replace << >> with the appropriate value
Dynamic-group
instance-dynamic-group
instance.compartment.id = '<<compartment OCID>>'
Policy
Allow dynamic-group instance-dynamic-group to manage compute-container-family in compartment <<compartmentt>>
Allow dynamic-group instance-dynamic-group to use virtual-network-family in compartment <<compartment>>
Allow dynamic-group instance-dynamic-group to read repos in compartment <<compartment>>
Container Instancesの作成
ここが本稼働環境のコアとなる部分です。一時ボリューム EMPTY_DIR を定義し、3つのコンテナを紐付けます。
Container InstancesのTerraform定義が以下です
## Replace << >> with the appropriate value
terraform {
required_version = ">= 1.5.0"
required_providers {
oci = {
source = "oracle/oci"
version = "~> 8.0"
}
}
}
provider "oci" {
auth = "InstancePrincipal"
region = var.region
}
variable "region" {
description = "OCI region used by the provider."
type = string
default = "ap-tokyo-1"
}
variable "compartment_id" {
description = "Compartment OCID for the container instance."
type = string
default = "<<Compartment OCID>>"
}
variable "subnet_id" {
description = "Subnet OCID for the container instance VNIC."
type = string
default = "<<Subnet OCID>>"
}
resource "oci_container_instances_container_instance" "nginx_rclone_fluentbit" {
compartment_id = var.compartment_id
display_name = "nginx-rclone-fluentbit"
availability_domain = "<<Availability_domain>>"
fault_domain = "FAULT-DOMAIN-1"
shape = "CI.Standard.E4.Flex"
shape_config {
ocpus = 1
memory_in_gbs = 1
}
vnics {
subnet_id = var.subnet_id
private_ip = "<<Private IP address>>"
is_public_ip_assigned = false
}
containers {
display_name = "nginx"
image_url = "docker.io/library/nginx:stable-alpine"
command = ["/bin/sh", "-c"]
arguments = [
"rm -f /var/log/nginx/access.log && touch /var/log/nginx/access.log; nginx -g 'daemon off;'"
]
environment_variables = {
MY_POD_NAME = "container-instance-01"
}
volume_mounts {
volume_name = "shared-html"
mount_path = "/usr/share/nginx/html"
}
volume_mounts {
volume_name = "shared-logs"
mount_path = "/var/log/nginx"
}
}
containers {
display_name = "rclone"
image_url = "docker.io/rclone/rclone:latest"
command = ["/bin/sh", "-c"]
arguments = [
<<-EOT
echo '--- START RCLONE COPY---' && mkdir -p /config/rclone && echo -e "[oci]
type = oracleobjectstorage
provider = resource_principal_auth
namespace = <<Namespace>>
compartment = <<Compartment OCID>>
region = ap-tokyo-1" > /config/rclone/rclone.conf && rclone copy oci:<<Bucket name>>/index.html /data && echo '---END RCLONE COPY ---'
EOT
]
volume_mounts {
volume_name = "shared-html"
mount_path = "/data"
}
}
containers {
display_name = "fluent-bit"
image_url = "docker.io/fluent/fluent-bit:3.2"
environment_variables = {
MY_POD_NAME = "container-instance-01"
}
volume_mounts {
volume_name = "shared-logs"
mount_path = "/var/log/nginx"
}
volume_mounts {
volume_name = "fluent-bit-config-volume"
mount_path = "/fluent-bit/etc"
}
}
volumes {
name = "shared-logs"
volume_type = "EMPTYDIR"
backing_store = "EPHEMERAL_STORAGE"
}
volumes {
name = "shared-html"
volume_type = "EMPTYDIR"
backing_store = "EPHEMERAL_STORAGE"
}
volumes {
name = "fluent-bit-config-volume"
volume_type = "CONFIGFILE"
configs {
file_name = "fluent-bit.conf"
data = base64encode(file("${path.module}/fluent-bit.conf"))
}
}
}
output "container_instance_id" {
description = "OCID of the OCI container instance."
value = oci_container_instances_container_instance.nginx_rclone_fluentbit.id
}
Fluent Bitの構成ファイルは以下のとおりです
## Replace << >> with the appropriate value
[SERVICE]
Flush 1
Daemon Off
Log_Level info
[INPUT]
Name tail
Path /var/log/nginx/access.log
Tag nginx.access
Parser none
[FILTER]
Name modify
Match *
Add pod_name ${MY_POD_NAME}
[OUTPUT]
Name syslog
Match *
Host <<Syslog server IP address>>
Port 514
Mode udp
syslog_format rfc3164
syslog_message_key log
syslog_facility_preset 1
syslog_severity_preset 6
syslog_hostname_key pod_name
syslog_appname_preset nginx-pod
ファイルが準備できたらTerraformを実行します
$ terraform init
Initializing the backend...
Initializing provider plugins...
:
$ terraform plan -out=tfplan
Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
:
$ terraform apply "tfplan"
oci_container_instances_container_instance.nginx_rclone_fluentbit: Creating...
oci_container_instances_container_instance.nginx_rclone_fluentbit: Still creating... [10s elapsed]
oci_container_instances_container_instance.nginx_rclone_fluentbit: Still creating... [20s elapsed]
oci_container_instances_container_instance.nginx_rclone_fluentbit: Still creating... [30s elapsed]
oci_container_instances_container_instance.nginx_rclone_fluentbit: Still creating... [40s elapsed]
oci_container_instances_container_instance.nginx_rclone_fluentbit: Creation complete after 49s [id=ocid1.computecontainerinstance.***]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
container_instance_id = "ocid1.computecontainerinstance.***"
動作確認
- Nginxへのアクセス確認
Object Storageにアップロードしたデータを表示することができました
- Syslogサーバーへのログ転送確認
NginxのログがSyslogサーバーに転送されています
[2026-07-12T22:11:14.632833+09:00] <14>Jul 12 13:11:13 container-instance-01 nginx-pod: 10.**.**.** - - [12/Jul/2026:13:11:13 +0000] "GET /index.html HTTP/1.1" 200 5349 "-" "****" "-"
[2026-07-12T22:11:14.632833+09:00] <14>Jul 12 13:11:14 container-instance-01 nginx-pod: 10.**.**.** - - [12/Jul/2026:13:11:14 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://****" "****" "-"
まとめ
OCI Container Instancesの「外部ストレージ直接マウント不可」および「標準ログ機能の不足」という実運用上の制約を、一時共有ボリューム(EMPTY_DIR)と2つのサイドカーコンテナ(Rclone/Fluent Bit)を組み合わせることで、Kubernetesなどの複雑な基盤を使うことなくシンプルに解決できることを検証しました
その他参考リンク
Fluent Bit Official Manual - Outputs
https://docs.fluentbit.io/manual/data-pipeline/outputs
OCIロギングとGrafanaを使用したHPC/GPUクラスタのログ監視方法
https://oracle-japan.github.io/ocitutorials/hpc/tech-knowhow/log-monitoring/