just using random at intervals and some shapekeys would be my guess…animating via replacemesh might work, but depending on the model and animation complexity might get more expensive than vertex animation.
another option is to have control over squashing and stretching with an armature…and semi randomizing the scale of the armature with
own.localScale.x = own.localScale.x + random.uniform(-0.001, 0.001)
own.localScale.y = own.localScale.y + random.uniform(-0.001, 0.001)
maybe on z axis as well with some clever weights to show some swelling at the apex of the bubble.
if this is done every frame it will just cause strange vibration behavior I tried it on a camera once to fake DOF, but without an extremely high FPS it makes your eyes scream in pain
it would need a better way to increment and decrement the scales over time, and to be clamped I guess…the scale would get higher as the bubbles get closer to the surface as well…
…anyway just some random thoughts.